<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Feed Aggregator on FromDual GmbH</title><link>https://www.fromdual.com/aggregator/</link><description>Recent content in Feed Aggregator on FromDual GmbH</description><generator>Hugo</generator><language>en-GB</language><managingEditor>oli.sennhauser@fromdual.com (Oli Sennhauser)</managingEditor><webMaster>oli.sennhauser@fromdual.com (Oli Sennhauser)</webMaster><copyright>© FromDual GmbH</copyright><lastBuildDate>Tue, 24 Mar 2026 10:46:00 +0100</lastBuildDate><atom:link href="https://www.fromdual.com/aggregator/index.xml" rel="self" type="application/rss+xml"/><item><title>Backup and Recovery Manager Release Notes</title><link>https://www.fromdual.com/blog/brman-release-notes/</link><pubDate>Tue, 24 Mar 2026 10:46:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/brman-release-notes/</guid><description>&lt;ul&gt;
&lt;li&gt;Backup and Recovery Manager 2.3.2 &lt;a href="https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.3.2-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 10 July 2025&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 2.3.1 &lt;a href="https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.3.1-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 12 August 2024&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 2.3.0 &lt;a href="https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.3.0-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 25 June 2024&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 2.2.5 &lt;a href="https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.2.5-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 23 February 2022&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 2.2.4 &lt;a href="https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.2.4-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 26 July 2021&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 2.2.3 &lt;a href="https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.2.3-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 13 January 2021&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 2.2.2 &lt;a href="https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.2.2-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 8 October 2020&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 2.2.1 &lt;a href="https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.2.1-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 5 August 2019&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 2.2.0 &lt;a href="https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.2.0-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 25 July 2019&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 2.1.0 &lt;a href="https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.1.0-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 22 February 2019&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 2.0.0 &lt;a href="https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.0.0-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 27 June 2018&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 1.2.5 &lt;a href="https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-1.2.5-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 1 May 2017&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 1.2.4 &lt;a href="https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-1.2.4-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 12 January 2017&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 1.2.3 &lt;a href="https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-1.2.3-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 1 October 2016&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 1.2.2 &lt;a href="https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-1.2.2-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 29 May 2015&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 1.2.1 &lt;a href="https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-1.2.1-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 18 January 2015&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 1.2.0, Release Date: 24 September 2014&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 1.1.1, Release Date: 4 September 2014&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 1.1.0, Release Date: 11 August 2014&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 1.0.4, Release Date: 15 April 2014&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 1.0.3, Release Date: 3 April 2014&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 1.0.2, Release Date: 10 December 2013&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 1.0.1, Release Date: 4 November 2013&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 1.0, Release Date: 30 September 2013&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.4, Release Date: 30 March 2011&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.3.6, Release Date: 23 January 2011&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.3.5, Release Date: 22 January 2011&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.3.4, Release Date: 21 November 2010&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.3.3, Release Date: 21 November 2010&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.3.2, Release Date: 14 November 2010&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.3.1, Release Date: 14 November 2010&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.3, Release Date: 13 November 2010&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.2.7, Release Date: 12 August 2010&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.2.6, Release Date: 12 August 2010&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.2.5, Release Date: 12 August 2010&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.2.4, Release Date: 12 August 2010&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.2.3, Release Date: 19 January 2010&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.2.2, Release Date: 7 January 2010&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.2.1, Release Date: 31 December 2009&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.2, Release Date: 24 December 2009&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.1.1, Release Date: 18 July 2008&lt;/li&gt;
&lt;li&gt;Backup and Recovery Manager 0.1, Release Date: 18 July 2008&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>MariaDB/MySQL Environment MyEnv 3.0.0 has been released</title><link>https://www.fromdual.com/blog/myenv-release-notes/fromdual-environment-myenv-3.0.0-has-been-released/</link><pubDate>Mon, 23 Mar 2026 17:42:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/myenv-release-notes/fromdual-environment-myenv-3.0.0-has-been-released/</guid><description>&lt;p&gt;FromDual has the pleasure to announce the release of the new version 3.0.0 of its popular MariaDB, MySQL and PostgreSQL multi-instance environment &lt;a href="https://www.fromdual.com/software/fromdual-myenv/" title="MariaDB, MySQL and PostgreSQL multi-instance environment"&gt;MyEnv&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The new MyEnv can be downloaded &lt;a href="https://support.fromdual.com/admin/public/download.php" target="_blank" title="FromDual download"&gt;here&lt;/a&gt;. How to install MyEnv is described in the &lt;a href="https://support.fromdual.com/documentation/myenv/myenv.html#installation-guide" target="_blank"&gt;MyEnv Installation Guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the inconceivable case that you find a bug in the MyEnv please report it to us by sending an &lt;a href="mailto:contact@fromdual.com?Subject=Bug report for myenv"&gt;email&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Any feedback, statements and testimonials are welcome as well! Please &lt;a href="mailto:feedback@fromdual.com?Subject=Feedback for fpmmm"&gt;send them to us&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="upgrade-from-2x-to-30"&gt;Upgrade from 2.x to 3.0&lt;/h2&gt;
&lt;p&gt;Please check the &lt;a href="https://support.fromdual.com/documentation/myenv/myenv.html#upgrade" target="_blank" title="Upgrading MyEnv"&gt;MyEnv Installation Guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="changes-in-myenv-300"&gt;Changes in MyEnv 3.0.0&lt;/h2&gt;
&lt;h3 id="myenv"&gt;MyEnv&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Template warning improved.&lt;/li&gt;
&lt;li&gt;Distro version in &lt;code&gt;--version&lt;/code&gt; added.&lt;/li&gt;
&lt;li&gt;Check MyEnv configuration permissions.&lt;/li&gt;
&lt;li&gt;#fd increased for MyEnv.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;myenv.conf&lt;/code&gt; should have more secure permissions now.&lt;/li&gt;
&lt;li&gt;Situation caught when &lt;code&gt;my.cnf&lt;/code&gt; is missing in &lt;code&gt;myenv.conf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Directories &lt;code&gt;home&lt;/code&gt; and &lt;code&gt;run&lt;/code&gt; moved to &lt;code&gt;dba&lt;/code&gt; and &lt;code&gt;myenv&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Unit file &lt;code&gt;mariadb.service&lt;/code&gt; and &lt;code&gt;mysql.service&lt;/code&gt; replaced by &lt;code&gt;dba.service&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;User &lt;code&gt;mysql&lt;/code&gt; replaced by &lt;code&gt;dba&lt;/code&gt; in template.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;start_stop&lt;/code&gt; fixed warning in case &lt;code&gt;argv[1]&lt;/code&gt; is missing.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sys_uid&lt;/code&gt; filter fixed for Rocky Linux.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dba&lt;/code&gt; unit file added to package.&lt;/li&gt;
&lt;li&gt;Nagios plugins detection removed from &lt;code&gt;showMyEnvVersion&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Old SysV init files removed and replaced by Systemd unit files.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dba&lt;/code&gt; user was introduced and check for system user added.&lt;/li&gt;
&lt;li&gt;User &lt;code&gt;dba&lt;/code&gt; changed an cosmetic fixes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="myenv-installer"&gt;MyEnv Installer&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;2 concurrent &lt;code&gt;installMyEnv&lt;/code&gt; versions cannot run any more.&lt;/li&gt;
&lt;li&gt;Directroy &lt;code&gt;binlog&lt;/code&gt;, &lt;code&gt;cgroups&lt;/code&gt; and &lt;code&gt;angel&lt;/code&gt; removed from &lt;code&gt;postgresql&lt;/code&gt; &lt;code&gt;type&lt;/code&gt; installation.&lt;/li&gt;
&lt;li&gt;Wrapper script &lt;code&gt;installMyEnv.sh&lt;/code&gt; removed.&lt;/li&gt;
&lt;li&gt;Cosmetics fixed in installer.&lt;/li&gt;
&lt;li&gt;Installation made more mysql friendly.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libaio1t64&lt;/code&gt; considered during installation recommendations on DEB systems.&lt;/li&gt;
&lt;li&gt;Next free port suggestion during &lt;code&gt;installMyEnv&lt;/code&gt; improved. It will suggest the first free port now.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;apt-get&lt;/code&gt; and &lt;code&gt;yum&lt;/code&gt; replaced by &lt;code&gt;apt&lt;/code&gt; and &lt;code&gt;dnf&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="myenv-utilities"&gt;MyEnv Utilities&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;insert_test.sh&lt;/code&gt; made PostgreSQL ready.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="postgresql"&gt;PostgreSQL&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;PostgreSQL instance is stopped with fast instead of immediate now.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;show_create_table.sh&lt;/code&gt; for PostgreSQL made nicer.&lt;/li&gt;
&lt;li&gt;PostgreSQL &lt;code&gt;status.sql&lt;/code&gt; added.&lt;/li&gt;
&lt;li&gt;Minor fixes for PostgreSQL.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="general"&gt;General&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CHANGELOG&lt;/code&gt; updated.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rc&lt;/code&gt; made unique.&lt;/li&gt;
&lt;li&gt;Minor bugs fixed.&lt;/li&gt;
&lt;li&gt;Copyright year updated from 2024 to 2026.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mkdir&lt;/code&gt; changed from &lt;code&gt;/bin&lt;/code&gt; to &lt;code&gt;/usr/bin&lt;/code&gt; which is the new/right standard on all our 3 supported distributions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="documentation"&gt;Documentation&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;README updated.&lt;/li&gt;
&lt;li&gt;Installation documentation improved, library related stuff documented.&lt;/li&gt;
&lt;li&gt;PostgreSQL added to documentation.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lsb_release&lt;/code&gt; removed from documentation.&lt;/li&gt;
&lt;li&gt;Documentation restructured.&lt;/li&gt;
&lt;li&gt;Documentation made more resilient agaist errors.&lt;/li&gt;
&lt;li&gt;Documentation process improved.&lt;/li&gt;
&lt;li&gt;Documentation moved completely to asciidoc.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="packaging"&gt;Packaging&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Package list completed.&lt;/li&gt;
&lt;li&gt;Makefile fixed.&lt;/li&gt;
&lt;li&gt;Old distro stuff and initV stuff removed.&lt;/li&gt;
&lt;li&gt;Build scripts fixed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For subscriptions of commercial use of MyEnv please &lt;a href="mailto:contact@fromdual.com?Subject=Commercial use of MyEnv"&gt;get in contact&lt;/a&gt; with us.&lt;/p&gt;</description></item><item><title>FromDual Performance Monitor 2.2.1 has been released</title><link>https://www.fromdual.com/blog/fpmmm-release-notes/fromdual-performance-monitor-2.2.1-has-been-released/</link><pubDate>Thu, 19 Feb 2026 18:18:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/fpmmm-release-notes/fromdual-performance-monitor-2.2.1-has-been-released/</guid><description>&lt;p&gt;FromDual has the pleasure to announce the release of the new version 2.2.1 of its popular Database Performance Monitor for MariaDB, Galera Cluster, MySQL and PostgreSQL &lt;a href="https://www.fromdual.com/software/fromdual-performance-monitor/"&gt;&lt;code&gt;fpmmm&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The FromDual Performance Monitor enables Database and System Administrators to monitor and understand what is going on inside their databases and on the machines where the databases reside.&lt;/p&gt;
&lt;p&gt;More information you can find here: &lt;a href="https://www.fromdual.com/software/fromdual-performance-monitor/"&gt;FromDual Performance Monitor&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="download"&gt;Download&lt;/h2&gt;
&lt;p&gt;The new FromDual Performance Monitor can be downloaded from our &lt;a href="https://support.fromdual.com/admin/public/download.php" target="_blank"&gt;Sofware Download&lt;/a&gt; page or you can use our &lt;a href="https://www.fromdual.com/repositories/"&gt;repositories&lt;/a&gt;. How to install and use the FromDual Performance Monitor is documented in the &lt;a href="https://support.fromdual.com/documentation/fpmmm/fpmmm.html" target="_blank"&gt;Documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the inconceivable case that you find a bug in the FromDual Performance Monitor please report it to us by sending an &lt;a href="mailto:contact@fromdual.com?Subject=Bug report for fpmmm"&gt;email&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Any feedback, statements and testimonials are welcome as well! Please send them &lt;a href="mailto:feedback@fromdual.com?Subject=Feedback for fpmmm"&gt;to us&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="monitoring-as-a-service-maas"&gt;Monitoring as a Service (MaaS)&lt;/h2&gt;
&lt;p&gt;You do not want to set-up your database monitoring yourself? No problem: Choose our &lt;a href="https://www.fromdual.com/services/monitoring-as-a-service-maas/"&gt;Monitoring as a Service&lt;/a&gt; (MaaS) to safe time and costs!&lt;/p&gt;
&lt;h2 id="installation-of-performance-monitor-221"&gt;Installation of Performance Monitor 2.2.1&lt;/h2&gt;
&lt;p&gt;How to install the FromDual Performance Monitor you can find in the &lt;a href="https://support.fromdual.com/documentation/fpmmm/fpmmm.html#installation-guide" target="_blank"&gt;Installation Guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="upgrade-of-fpmmm-tar-ball-from-1x-to-221"&gt;Upgrade of fpmmm tar ball from 1.x to 2.2.1&lt;/h2&gt;
&lt;p&gt;There are some changes in the configuration file (&lt;code&gt;fpmmm.conf&lt;/code&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The access rights should be change as follows: &lt;code&gt;chmod 600 /etc/fpmmm.conf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The key &lt;code&gt;Methode&lt;/code&gt; was spelled wrong in the configuration file. It was renamed to &lt;code&gt;Method&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The key &lt;code&gt;PidFile&lt;/code&gt; is ambiguous which could lead to problems and bugs. Thus it was changed to either &lt;code&gt;MyPidFile&lt;/code&gt; for fpmmm and &lt;code&gt;DbPidFile&lt;/code&gt; for the database.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Upgrade with DEB/RPM packages should happen automatically. For tar balls follow this instruction:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cd /opt
$ tar xf /download/fpmmm-2.2.1.tar.gz
$ rm -f fpmmm
$ ln -s fpmmm-2.2.1 fpmmm
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="changes-in-fromdual-performance-monitor-221"&gt;Changes in FromDual Performance Monitor 2.2.1&lt;/h2&gt;
&lt;p&gt;These release notes include both the changes that came with version 2.2.0 and version 2.2.1.&lt;/p&gt;
&lt;p&gt;This release contains new features and various bug fixes.&lt;/p&gt;
&lt;p&gt;You can verify your current FromDual Performance Monitor version with the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ /opt/fpmmm/bin/fpmmm --version
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="general"&gt;General&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Updated to latest myEnv library.&lt;/li&gt;
&lt;li&gt;PHP 8.5 incompatibilities fixed.&lt;/li&gt;
&lt;li&gt;Typos fixed.&lt;/li&gt;
&lt;li&gt;Error messages improved.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;real_connect&lt;/code&gt; warnings send to console are suppressed now.&lt;/li&gt;
&lt;li&gt;Connection problems timeout reduced so in case of troubles we should see more and earlier&amp;hellip;&lt;/li&gt;
&lt;li&gt;Other cosmetic errors and debugging information fixed.&lt;/li&gt;
&lt;li&gt;Data are gathered and set to zero even thought database is not reachable.&lt;/li&gt;
&lt;li&gt;Indention of logged messages fixed.&lt;/li&gt;
&lt;li&gt;Function exit is logged now as well.&lt;/li&gt;
&lt;li&gt;SSL connection handling added.&lt;/li&gt;
&lt;li&gt;Fix of error: array_sum(): Addition is not supported on type string in warning after upgrade to Ubuntu 24.04/PHP 8.3.&lt;/li&gt;
&lt;li&gt;Error log parsing had problems with huge error logs. Now we have added a size barrier.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;getDistributions&lt;/code&gt; updated/cleaned-up.&lt;/li&gt;
&lt;li&gt;Command lsb_release removed.&lt;/li&gt;
&lt;li&gt;Documentation added.&lt;/li&gt;
&lt;li&gt;Nagios: Tests fixed for MariaDB 11.8.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="templates"&gt;Templates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Server: Available I/O system information added to each I/O system on top, pages named.&lt;/li&gt;
&lt;li&gt;InnoDB: Pages named, row write operations graph added.&lt;/li&gt;
&lt;li&gt;MySQL: Some graphs and query dashboard made nicer.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="agent"&gt;Agent&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;none&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="server"&gt;Server&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Items &lt;code&gt;FromDual.MySQL.server.disk.avg_io_read_wait&lt;/code&gt; and &lt;code&gt;FromDual.MySQL.server.disk.avg_io_write_wait&lt;/code&gt; removed because they are showing completely wrong values. Use &lt;code&gt;FromDual.MySQL.server.disk.r_await&lt;/code&gt; and &lt;code&gt;FromDual.MySQL.server.disk.w_await&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;Workaround for missing cpuinfo old cachefile implemented.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="galera"&gt;Galera&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Old style variable fixed which causes problems with newer version.&lt;/li&gt;
&lt;li&gt;Default values on database stop added.&lt;/li&gt;
&lt;li&gt;Workaround for cut &lt;code&gt;wsrep_provider_options&lt;/code&gt; bug in MySQL Galera Cluster added.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="innodb"&gt;InnoDB&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Variable &lt;code&gt;innodb_log_file_size&lt;/code&gt; made consistent for MariaDB and MySQL.&lt;/li&gt;
&lt;li&gt;Deprecated and removed variable &lt;code&gt;innodb_log_files_in_group&lt;/code&gt; removed.&lt;/li&gt;
&lt;li&gt;Fix for &lt;code&gt;innodb_log_file_size&lt;/code&gt; in MySQL 9.4.&lt;/li&gt;
&lt;li&gt;Log occupancy graph added and graph added to dashboard.&lt;/li&gt;
&lt;li&gt;Variable &lt;code&gt;tx_isolation&lt;/code&gt; replaced by transaction isolation which is deprecated in MariaDB 11.2 and MySQL 5.7.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="mysql"&gt;MySQL&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Variable &lt;code&gt;vendor_versions_behind&lt;/code&gt; special case caught.&lt;/li&gt;
&lt;li&gt;Connection charset changed from &lt;code&gt;utf8&lt;/code&gt; to &lt;code&gt;utf8mb4&lt;/code&gt; due to errors in MariaDB 11.8.&lt;/li&gt;
&lt;li&gt;Template pages named.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="process"&gt;Process&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;none&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="security"&gt;Security&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Module improved for new behaviour in MariaDB 11.8.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="master"&gt;Master&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Wrong version check for master fixed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="slave"&gt;Slave&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Slave lagging problem fixed.&lt;/li&gt;
&lt;li&gt;Wrong version check for slave fixed.&lt;/li&gt;
&lt;li&gt;MySQL 8.4 commands added for replication monitoring.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="backup"&gt;Backup&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;none&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="postgresql"&gt;PostgreSQL&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Rudimentary PostgreSQL monitoring added.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="packaging"&gt;Packaging&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;RHEL 8 added again.&lt;/li&gt;
&lt;li&gt;RPM spec adapted for RHEL 10.&lt;/li&gt;
&lt;li&gt;SNMP library updated.&lt;/li&gt;
&lt;li&gt;Debian 10 and RHEL 7 removed.&lt;/li&gt;
&lt;li&gt;DEB sign stuff added.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For subscriptions of commercial use of &lt;code&gt;fpmmm&lt;/code&gt; please &lt;a href="mailto:contact@fromdual.com?Subject=Commercial use of fpmmm"&gt;get in contact&lt;/a&gt; with us.&lt;/p&gt;</description></item><item><title>What is the quickest way to load data into the database?</title><link>https://www.fromdual.com/blog/load-data-quick-into-the-database/</link><pubDate>Wed, 11 Feb 2026 10:04:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/load-data-quick-into-the-database/</guid><description>&lt;p&gt;We had some really exciting problems to solve for the last customer! Especially because the database wasn&amp;rsquo;t exactly small.&lt;/p&gt;
&lt;p&gt;Here are some key data: CPU: 2 sockets x 24 cores x 2 threads = 96 vCores, 756 G RAM, 2 x 10 Tbyte PCIe SSD in RAID-10 and 7 Tbyte data, several thousand clients, rapidly growing.&lt;/p&gt;
&lt;p&gt;The current throughput: 1 M &lt;code&gt;SELECT&lt;/code&gt;/min, 56 k &lt;code&gt;INSERT&lt;/code&gt;/min, 44 k &lt;code&gt;UPDATE&lt;/code&gt;/min, 7 k &lt;code&gt;DELETE&lt;/code&gt;/min averaged over 30 days. With a strong upward trend. Application and queries not consistently optimised. Database configuration: ‘state of the art’ not verified with benchmarks. CPU utilisation approx. 50% on average, more at peak times. I/O system still has available resources.&lt;/p&gt;
&lt;p&gt;The customer collects position and other device data and stores it in the database. In other words, a classic IoT problem (with time series, index clustered table, etc.).&lt;/p&gt;
&lt;p&gt;The question he has asked is: What is the fastest way to copy data from one table (pending data, a kind of queue) to another table (final data, per client)?&lt;/p&gt;
&lt;p&gt;The data flow looks something like this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;+------------+
| IoT Device |--+
+------------+ \
 \ +-----+
+------------+ \ | AS | +--------------+ Processing +------------+
| IoT Device |------+--&amp;gt;| |--&amp;gt;| Pending data |-------------&amp;gt;| Final data |
+------------+ / | 400 | +--------------+ of data +------------+
 / +-----+
+------------+ /
| IoT Device |--+
+------------+
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;3 different variants to copy the data were available for selection.&lt;/p&gt;
&lt;h2 id="variant-1-insert-and-delete-simplest-form"&gt;Variant 1: &lt;code&gt;INSERT&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt; (simplest form)&lt;/h2&gt;
&lt;p&gt;The simplest variant is a simple &lt;code&gt;INSERT&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt;. This variant is particularly problematic because MariaDB/MySQL and PostgreSQL have &lt;code&gt;AUTOCOMMIT&lt;/code&gt; enabled by default (&lt;a href="https://dev.mysql.com/doc/refman/8.4/en/innodb-autocommit-commit-rollback.html" target="_blank"&gt;here&lt;/a&gt;, &lt;a href="https://mariadb.com/docs/server/reference/sql-statements/transactions/start-transaction" target="_blank"&gt;here&lt;/a&gt;, &lt;a href="https://www.postgresql.org/docs/current/ecpg-sql-set-autocommit.html" target="_blank"&gt;here&lt;/a&gt; and &lt;a href="https://www.cybertec-postgresql.com/en/disabling-autocommit-in-postgresql-can-damage-your-health/" target="_blank"&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;To help you visualise this a little better, here is some pseudocode:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;// 20k rows
for (i = 1; i &amp;lt;= 2000; i++) {

 SELECT * FROM pending LIMIT 10;
 foreach ( row ) {
 INSERT INTO final;
 -- implicit COMMIT
 DELETE FROM pending WHERE id = row[id];
 -- implicit COMMIT
 }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So if we want to copy 20 k rows, this variant causes: 40 k &lt;code&gt;COMMIT&lt;/code&gt;s (&lt;code&gt;fsync&lt;/code&gt;) and 42 k network round trips!&lt;/p&gt;
&lt;h2 id="variant-2-start-transaction-and-insert-ad-delete"&gt;Variant 2: &lt;code&gt;START TRANSACTION&lt;/code&gt; and &lt;code&gt;INSERT&lt;/code&gt; ad &lt;code&gt;DELETE&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;This variant is used by more experienced database developers. Here is the corresponding pseudocode:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;// 20k rows
for (i = 1; i &amp;lt;= 2000; i++) {

 SELECT * FROM pending LIMIT 10;
 START TRANSACTION;
 foreach ( row ) {
 INSERT INTO final;
 DELETE FROM pending WHERE id = row[id];
 }
 COMMIT;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we want to copy 20 k rows in this example, this variant only causes 2 k &lt;code&gt;COMMIT&lt;/code&gt;s (&lt;code&gt;fsync&lt;/code&gt;)! So 20 times less! But 46 k network round trips (10% more).&lt;/p&gt;
&lt;h2 id="variant-3-start-transaction-and-optimised-insert-and-delete"&gt;Variant 3: &lt;code&gt;START TRANSACTION&lt;/code&gt; and optimised &lt;code&gt;INSERT&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;This variant is a little more demanding in terms of programming. It is used if you want to get a little closer to the limits of what is possible. Here is the pseudo code:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;// 20k rows
for (i = 1; i &amp;lt;= 2000; i++) {

 SELECT * FROM pending LIMIT 10;
 START TRANSACTION;
 INSERT INTO final (), (), (), (), (), (), (), (), (), ();
 DELETE FROM pending WHERE id = IN (...);
 COMMIT;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And this 3rd variant also only causes 2 k &lt;code&gt;COMMIT&lt;/code&gt;&amp;rsquo;s (&lt;code&gt;fsync&lt;/code&gt;) with 20 k rows, but saves the loop via the &lt;code&gt;INSERT&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt; statements in the database. So on the one hand we save network round trips (only 10 k) and CPU cycles on the database (which are difficult to scale) for parsing the queries.&lt;/p&gt;
&lt;h2 id="test-set-up"&gt;Test set-up&lt;/h2&gt;
&lt;p&gt;To test the whole thing, we have prepared a small script: &lt;a href="https://www.fromdual.com/code-examples/load_data.php.txt"&gt;load_data.php&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="preparation-and-execution-with-mariadbmysql"&gt;Preparation and execution with MariaDB/MySQL&lt;/h3&gt;
&lt;p&gt;You can execute these tests yourself with the following commands:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;SQL&amp;gt; CREATE DATABASE test;
SQL&amp;gt; CREATE USER &amp;#39;app&amp;#39;@&amp;#39;127.0.0.1&amp;#39; IDENTIFIED BY &amp;#39;secret&amp;#39;;
SQL&amp;gt; GRANT ALL ON *.* TO &amp;#39;app&amp;#39;@&amp;#39;127.0.0.1&amp;#39;;

$ ./load_data.php --database-type=mysql --database=test --host=127.0.0.1 --port=3306 --user=app --password=secret --prepare

$ for i in $(seq 5) ; do
 ./load_data.php --database-type=mysql --database=test --host=127.0.0.1 --port=3306 --user=app --password=secret --run --variant=1
 ./load_data.php --database-type=mysql --database=test --host=127.0.0.1 --port=3306 --user=app --password=secret --run --variant=2
 ./load_data.php --database-type=mysql --database=test --host=127.0.0.1 --port=3306 --user=app --password=secret --run --variant=3
done

$ ./load_data.php --database-type=mysql --database=test --host=127.0.0.1 --port=3306 --user=app --password=secret --clean-up
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Everyone can work out the measured values themselves with the corresponding test script.&lt;/p&gt;
&lt;h3 id="preparation-and-execution-with-postgresql"&gt;Preparation and execution with PostgreSQL&lt;/h3&gt;
&lt;p&gt;You can execute these tests yourself with the following commands:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;postgres# CREATE DATABASE test;
postgres# CREATE USER app PASSWORD &amp;#39;secret&amp;#39;;
postgres# GRANT ALL ON DATABASE test TO app;
postgres# GRANT ALL ON SCHEMA public TO app;

$ ./load_data.php --database-type=postgresql --database=test --host=127.0.0.1 --port=5432 --user=app --password=secret --prepare

$ for i in $(seq 5) ; do
 ./load_data.php --database-type=postgresql --database=test --host=127.0.0.1 --port=5432 --user=app --password=secret --run --variant=1
 ./load_data.php --database-type=postgresql --database=test --host=127.0.0.1 --port=5432 --user=app --password=secret --run --variant=2
 ./load_data.php --database-type=postgresql --database=test --host=127.0.0.1 --port=5432 --user=app --password=secret --run --variant=3
done

$ ./load_data.php --database-type=postgresql --database=test --host=127.0.0.1 --port=5432 --user=app --password=secret --clean-up
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Anyone can work out the measured values themselves with the corresponding test script.&lt;/p&gt;
&lt;h2 id="results"&gt;Results&lt;/h2&gt;
&lt;p&gt;To avoid unnecessary discussions, we have ‘only’ listed the relative performance (runtime) here, as MarkC has been doing recently. We are happy to provide our measured values bilaterally. However, they can be easily reproduced with the test script itself.&lt;/p&gt;
&lt;p&gt;Less is better:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;/th&gt;
 &lt;th&gt;Variant 1&lt;/th&gt;
 &lt;th&gt;Variant 2&lt;/th&gt;
 &lt;th&gt;Variant 3&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;MariaDB 11.8, avg(5)&lt;/td&gt;
 &lt;td&gt;100.0%&lt;/td&gt;
 &lt;td&gt;7.5%&lt;/td&gt;
 &lt;td&gt;6.2%&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;PostgreSQL 19dev, avg(5)&lt;/td&gt;
 &lt;td&gt;100.0%&lt;/td&gt;
 &lt;td&gt;11.2%&lt;/td&gt;
 &lt;td&gt;7.0%&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Attention&lt;/strong&gt;: The values of MariaDB/MySQL and PostgreSQL can NOT be compared directly!&lt;/p&gt;
&lt;br&gt;
&lt;p&gt;And here is the graphical evaluation:&lt;/p&gt;
&lt;img src="https://www.fromdual.com/images/mariadb-data-load.png" alt="mariadb"&gt;
&lt;p&gt; &lt;/p&gt;
&lt;img src="https://www.fromdual.com/images/postgresql-data-load.png" alt="postgresql"&gt;
&lt;h2 id="remarks"&gt;Remarks&lt;/h2&gt;
&lt;p&gt;With faster discs, the difference between 1 and 2/3 would probably not have been quite so significant. Customer tests have shown a difference of ‘only’ about a factor of 5 (instead of a factor of 9 to 16).&lt;/p&gt;
&lt;p&gt;There are certainly other ways in which this loading process can be optimised. Here are a few that come to mind:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;INSERT INTO ... SELECT * FROM&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LOAD DATA INFILE&lt;/code&gt;/&lt;code&gt;COPY&lt;/code&gt;, if possible&lt;/li&gt;
&lt;li&gt;Prepared statements&lt;/li&gt;
&lt;li&gt;Server side Stored Language (SQL/PSM, PL/pgSQL, &amp;hellip;) :-(&lt;/li&gt;
&lt;li&gt;PDO-Fetch of the results?&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Maybe I should look for a profiler (&lt;a href="https://xdebug.org/" target="_blank"&gt;Xdebug&lt;/a&gt; or &lt;a href="https://www.php.net/manual/en/book.xhprof.php" target="_blank"&gt;xhprof&lt;/a&gt;)?&lt;/p&gt;
&lt;h2 id="further-contributions"&gt;Further contributions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/load-csv-files-into-the-database/"&gt;Load CSV files into the database&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/mariadb-prepared-statements-transactions-and-multi-row-inserts/"&gt;MariaDB Prepared Statements, Transactions and Multi-Row Inserts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/how-good-is-mysql-insert-trigger-performance/"&gt;How good is MySQL INSERT TRIGGER performance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This page was translated using &lt;a href="https://www.deepl.com/en/translator" target="_blank"&gt;deepl.com&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Marko Mäkelä mentioned you on MDEV-38779</title><link>https://www.fromdual.com/blog/mariadb-dynamically-configurable-buffer-pool-broken/comment-1049/</link><pubDate>Wed, 11 Feb 2026 08:37:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/mariadb-dynamically-configurable-buffer-pool-broken/comment-1049/</guid><description>&lt;p&gt;[~oli], thank you for your report. There already was an existing report MDEV-38671 about mostly the same, namely that the {{innodb_buffer_pool_size}} cannot be increased anymore when MariaDB Server has been started with the default settings.&lt;/p&gt;
&lt;p&gt;I have updated MDEV-38671 with some more explanation why this change was made and why the parameter {{innodb_buffer_pool_size_max}} was introduced. My biggest motivation to implement this were the crash MDEV-35485, which we constantly hit in our internal stress testing, and the need to make MDEV-24670 behave in a meaningful and predictable way, that is, actually release memory to the operating system in the event of a memory pressure event. By default, that new 10.11 feature is disabled by default, but it can be enabled by {{SET GLOBAL innodb_buffer_pool_size_auto_min}}.&lt;/p&gt;</description></item><item><title>MariaDB has broken the concept of dynamically configurable buffer pools!</title><link>https://www.fromdual.com/blog/mariadb-dynamically-configurable-buffer-pool-broken/</link><pubDate>Mon, 09 Feb 2026 19:14:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/mariadb-dynamically-configurable-buffer-pool-broken/</guid><description>&lt;h2 id="problem-description"&gt;Problem description&lt;/h2&gt;
&lt;p&gt;MySQL introduced the dynamically configurable InnoDB buffer pool with 5.7.5 in September 2014 (&lt;a href="https://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-5.html" target="_blank"&gt;here&lt;/a&gt; and &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/innodb-buffer-pool-resize.html#innodb-buffer-pool-online-resize" target="_blank"&gt;here&lt;/a&gt;):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The innodb_buffer_pool_size configuration option can be set dynamically using a SET statement, allowing you to resize the buffer pool without restarting the server. For example:&lt;br&gt;&lt;br&gt;
mysql&amp;gt; SET GLOBAL innodb_buffer_pool_size=402653184;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;MariaDB 10.2.2 adopted this feature in September 2016 (&lt;a href="https://mariadb.com/docs/release-notes/community-server/old-releases/10.2/10.2.2#notable-changes" target="_blank"&gt;source&lt;/a&gt;):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;InnoDB was merged from MySQL-5.7.14 (XtraDB is disabled in MariaDB-10.2.2 pending a similar merge)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The problematic thing is, on the one hand, that this feature now no longer works as it did before and no longer works as expected. On the other hand, they changed the behaviour in spring 2025 within a major release series (LTS), which in my opinion is an absolute no-go (&lt;a href="https://mariadb.com/docs/server/server-usage/storage-engines/innodb/innodb-buffer-pool#buffer-pool-changes" target="_blank"&gt;source&lt;/a&gt;):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;From MariaDB 10.11.12 / 11.4.6 / 11.8.2, there are significant changes to the InnoDB buffer pool behavior.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And what is more, the description of this is quite poor (&lt;a href="https://mariadb.com/docs/release-notes/community-server/10.11/10.11.12#innodb" target="_blank"&gt;source&lt;/a&gt;):&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;decreasing innodb_buffer_pool_size at runtime does not release memory (MDEV-32339)&lt;/li&gt;
&lt;li&gt;reorganise innodb buffer pool (and remove buffer pool chunks) (MDEV-29445)&lt;/li&gt;
&lt;li&gt;The Linux memory pressure interface, which could previously not be disabled and could cause performance anomalies, was rewritten and is disabled by default. (MDEV-34863)&lt;/li&gt;
&lt;li&gt;Server crashes when resizing default innodb buffer pool after setting innodb-buffer-pool-chunk-size to 1M (MDEV-34677)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the corresponding worklog (&lt;a href="https://jira.mariadb.org/browse/MDEV-36197" target="_blank"&gt;MDEV-36197&lt;/a&gt;) MarkoM also describes a different behaviour:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;innodb_buffer_pool_size_auto_max (my proposal for this task) would set the maximum for the automation (default: 0 to disable the logic).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;which would have made much more sense in my opinion.&lt;/p&gt;
&lt;h2 id="how-did-it-work-before"&gt;How did it work before?&lt;/h2&gt;
&lt;p&gt;How did it work in the past with MariaDB and still today with MySQL:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;SQL&amp;gt; SHOW GLOBAL VARIABLES LIKE &amp;#39;innodb_buffer_pool%size&amp;#39;;
+-------------------------------+-----------+
| Variable_name | Value |
+-------------------------------+-----------+
| innodb_buffer_pool_chunk_size | 2097152 |
| innodb_buffer_pool_size | 134217728 |
+-------------------------------+-----------+

SQL&amp;gt; SET GLOBAL innodb_buffer_pool_size = @@innodb_buffer_pool_chunk_size * 128;

SQL&amp;gt; SHOW GLOBAL VARIABLES LIKE &amp;#39;innodb_buffer_pool%size&amp;#39;;
+-------------------------------+-----------+
| Variable_name | Value |
+-------------------------------+-----------+
| innodb_buffer_pool_chunk_size | 2097152 |
| innodb_buffer_pool_size | 268435456 |
+-------------------------------+-----------+
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Thus everything OK. Works as expected and as usual.&lt;/p&gt;
&lt;h2 id="what-does-mariadb-do-today"&gt;What does MariaDB do today?&lt;/h2&gt;
&lt;p&gt;What happens today with MariaDB:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;SQL&amp;gt; SHOW GLOBAL VARIABLES LIKE &amp;#39;innodb_buffer_pool%size%&amp;#39;;
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| innodb_buffer_pool_chunk_size | 0 |
| innodb_buffer_pool_size | 134217728 |
| innodb_buffer_pool_size_auto_min | 134217728 |
| innodb_buffer_pool_size_max | 134217728 |
+----------------------------------+-----------+

SQL&amp;gt; SET GLOBAL innodb_buffer_pool_size = 256*1024*1024;
Query OK, 0 rows affected, 1 warning (0.000 sec)

SQL&amp;gt; show warnings;
+---------+------+----------------------------------------------------------------+
| Level | Code | Message |
+---------+------+----------------------------------------------------------------+
| Warning | 1292 | Truncated incorrect innodb_buffer_pool_size value: &amp;#39;268435456&amp;#39; |
+---------+------+----------------------------------------------------------------+

SQL&amp;gt; SHOW GLOBAL VARIABLES LIKE &amp;#39;innodb_buffer_pool%size%&amp;#39;;
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| innodb_buffer_pool_chunk_size | 0 |
| innodb_buffer_pool_size | 134217728 |
| innodb_buffer_pool_size_auto_min | 134217728 |
| innodb_buffer_pool_size_max | 134217728 |
+----------------------------------+-----------+
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So nothing at all! Not even an error, just a warning. And if I do not look closely, I do not even realise that something did not work.&lt;/p&gt;
&lt;p&gt;The MariaDB error log says:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;[Note] InnoDB: Memory pressure event disregarded; innodb_buffer_pool_size=128m, innodb_buffer_pool_size_auto_min=128m
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you then do some searching, you find out that something has changed here: &lt;a href="https://mariadb.com/docs/server/server-usage/storage-engines/innodb/innodb-buffer-pool#buffer-pool-changes" target="_blank"&gt;Buffer Pool Changes&lt;/a&gt; and try intuitively:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;SQL&amp;gt; SET GLOBAL innodb_buffer_pool_size_max = 256*1024*1024;
ERROR 1238 (HY000): Variable &amp;#39;innodb_buffer_pool_size_max&amp;#39; is a read only variable
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But that does not work either.&lt;/p&gt;
&lt;p&gt;This means you have to restart the database! And possibly at the very moment when you do not actually want to restart the database and need this feature&amp;hellip;&lt;/p&gt;
&lt;p&gt;The documentation also states ((&lt;a href="https://mariadb.com/docs/server/server-usage/storage-engines/innodb/innodb-system-variables#innodb_buffer_pool_size_max" target="_blank" title="innodb_buffer_pool_size_max"&gt;source&lt;/a&gt;):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Default Value: specified by the initial value of innodb_buffer_pool_size, rounded up to the block size of that variable. See the section about buffer pool changes in MariaDB 10.11.12, 11.4.6, and 11.8.2.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and (&lt;a href="https://mariadb.com/docs/server/server-usage/storage-engines/innodb/innodb-buffer-pool#buffer-pool-changes" target="_blank" title="Buffer Pool Changes"&gt;source&lt;/a&gt;):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If innodb_buffer_pool_size_max is 0 or not specified, it defaults to the innodb_buffer_pool_size value.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This means that I have to think again beforehand about how big I should make &lt;code&gt;innodb_buffer_pool_size_max&lt;/code&gt; and can only correct it afterwards during operation, should I have forgotten or misjudged it.&lt;/p&gt;
&lt;p&gt;In my opinion, this is a complete step backwards from an operational point of view. This is probably another implementation for some cloud-only as a service solution (enterprise?).&lt;/p&gt;
&lt;p&gt;My suggestion is: Either, as suggested in the MDEV: 0 should switch off this feature and the behaviour should be as before or the default value should be set to 75% of the RAM size, as &lt;code&gt;innodb_dedicated_server&lt;/code&gt; does with MySQL.&lt;/p&gt;
&lt;p&gt;I had the audacity to open a bug here: &lt;a href="https://jira.mariadb.org/browse/MDEV-38779" target="_blank"&gt;New InnoDB Buffer Pool autosize feature not so optimal implemented&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;FedericoR has thankfully recommended the following link: &lt;a href="https://www.mail-archive.com/developers@lists.mariadb.org/msg00822.html" target="_blank" title="MariaDB developers mailing list"&gt;Issues with new buffer pool configuration in MariaDB Minors (10.11.12/13/14, 11.4.6/7/8, 11.8.2/3)&lt;/a&gt;. I do not seem to be the only one who was annoyed by this change&amp;hellip;&lt;/p&gt;
&lt;h2 id="how-does-postgresql-do-this"&gt;How does PostgreSQL do this?&lt;/h2&gt;
&lt;p&gt;PostgreSQL is currently not (yet) able to change &lt;code&gt;shared_buffers&lt;/code&gt; dynamically. The default is usually 128M. The rule of thumb here, similar to MyISAM, is 25 - 40% of RAM. The lack of this feature is probably not as serious with PostgreSQL, however, as PostgreSQL relies heavily on the file system cache, similar to MyISAM.&lt;/p&gt;
&lt;p&gt;Source: &lt;a href="https://www.postgresql.org/docs/current/runtime-config-resource.html#RUNTIME-CONFIG-RESOURCE-MEMORY" target="_blank"&gt;Resource Consumption&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This page was translated using &lt;a href="https://www.deepl.com/en/translator" target="_blank"&gt;deepl.com&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>How much space does NULL need?</title><link>https://www.fromdual.com/blog/how-much-space-does-null-need/</link><pubDate>Sun, 08 Feb 2026 16:15:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/how-much-space-does-null-need/</guid><description>&lt;p&gt;The last time I consulted a customer, he came up to me beaming with joy and said that he had taken my advice and changed all the primary key columns from &lt;code&gt;BIGINT&lt;/code&gt; (8 bytes) to &lt;code&gt;INT&lt;/code&gt; (4 bytes) and that had made a big difference! His MySQL 8.4 database is now 750 Gbyte smaller (from 5.5 Tbyte). Nice!&lt;/p&gt;
&lt;p&gt;And yes, I know that contradicts the recommendations of some of my PostgreSQL colleagues (&lt;a href="https://www.crunchydata.com/blog/postgres-serials-should-be-bigint-and-how-to-migrate" target="_blank"&gt;here&lt;/a&gt; and &lt;a href="https://www.cybertec-postgresql.com/en/uuid-serial-or-identity-columns-for-postgresql-auto-generated-primary-keys/#should-i-use-integerserial-or-bigintbigserial-for-my-auto-generated-primary-key" target="_blank"&gt;here&lt;/a&gt;). In the MySQL world, more emphasis is placed on such things (&lt;a href="https://dev.mysql.com/doc/refman/8.4/en/data-size.html" target="_blank"&gt;source&lt;/a&gt;):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Use the most efficient (smallest) data types possible. MySQL has many specialized types that save disk space and memory. For example, use the smaller integer types if possible to get smaller tables&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Also, InnoDB works a wee bit differently (index clustered table and primary key in all secondary keys) than PostgreSQL (heap table, indices with row pointer (&lt;code&gt;ctid&lt;/code&gt;)).&lt;/p&gt;
&lt;p&gt;But that&amp;rsquo;s not really the issue. Immediately afterwards, he asked me whether the deletion of columns of type &lt;code&gt;DOUBLE&lt;/code&gt; (8 bytes, in PostgreSQL-speak &lt;code&gt;DOUBLE PRECISION&lt;/code&gt;) would also save space or whether he should rather drop the columns straight away. My first reflex response to &lt;code&gt;DOUBLE&lt;/code&gt; was: &lt;code&gt;NULL&lt;/code&gt; is good, followed by &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; (&lt;code&gt;VACUUM FULL&lt;/code&gt; in PostgreSQL parlance). But the second thought was, &lt;code&gt;DOUBLE&lt;/code&gt; is a data type of fixed length, does &lt;code&gt;NULL&lt;/code&gt; also apply there or only for data types with variable length? Caution is the mother of the porcelain box! Love to consult the manual first&amp;hellip;&lt;/p&gt;
&lt;p&gt;And there it says (&lt;a href="https://dev.mysql.com/doc/refman/8.4/en/data-size.html" target="_blank"&gt;source&lt;/a&gt;):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Declare columns to be NOT NULL if possible. It makes SQL operations faster, by enabling better use of indexes and eliminating overhead for testing whether each value is NULL. You also save some storage space, one bit per column. If you really need NULL values in your tables, use them. Just avoid the default setting that allows NULL values in every column.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and (&lt;a href="https://dev.mysql.com/doc/refman/8.4/en/innodb-row-format.html" target="_blank"&gt;source&lt;/a&gt;):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The variable-length part of the record header contains a bit vector for indicating NULL columns. &amp;hellip; Columns that are NULL do not occupy space other than the bit in this vector. The variable-length part of the header also contains the lengths of variable-length columns. Each length takes one or two bytes, depending on the maximum length of the column. If all columns in the index are NOT NULL and have a fixed length, the record header has no variable-length part.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="experiment-with-mariadbmysql"&gt;Experiment with MariaDB/MySQL&lt;/h2&gt;
&lt;h3 id="test-setup"&gt;Test setup&lt;/h3&gt;
&lt;p&gt;Somehow the description is a bit too complicated for me. Perhaps a small sketch would help? So let&amp;rsquo;s give it a try:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;SQL&amp;gt; -- DROP TABLE IF EXISTS tracking;

SQL&amp;gt; CREATE TABLE tracking (
 id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT
, d0 DOUBLE, d1 DOUBLE, d2 DOUBLE, d3 DOUBLE, d4 DOUBLE
, d5 DOUBLE, d6 DOUBLE, d7 DOUBLE, d8 DOUBLE, d9 DOUBLE
);

SQL&amp;gt; INSERT INTO tracking SELECT NULL, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0;
SQL&amp;gt; INSERT INTO tracking SELECT NULL, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 FROM tracking;
... bis 16 M rows
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The table is approx. 1.8 Gbyte in size for both MariaDB and MySQL with 16 M rows. Since this information is only given very imprecisely in &lt;code&gt;INFORMATION_SCHEMA&lt;/code&gt;, let&amp;rsquo;s take a look at the file system:&lt;/p&gt;
&lt;p&gt;MariaDB 11.8:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;SQL&amp;gt; system ls -l tracking.ibd
-rw-rw---- 1 mysql mysql 1206 Feb 7 10:28 tracking.frm
-rw-rw---- 1 mysql mysql 1933574144 Feb 7 10:32 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;MySQL 8.4:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;SQL&amp;gt; system ls -l tracking.ibd
-rw-r----- 1 mysql mysql 1929379840 Feb 7 10:33 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="defragment-the-table"&gt;Defragment the table&lt;/h3&gt;
&lt;p&gt;Then we ‘defragment’ the table with the &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; command:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;SQL&amp;gt; OPTIMIZE TABLE tracking;
+---------------+----------+----------+-------------------------------------------------------------------+
| Table | Op | Msg_type | Msg_text |
+---------------+----------+----------+-------------------------------------------------------------------+
| test.tracking | optimize | note | Table does not support optimize, doing recreate + analyze instead |
| test.tracking | optimize | status | OK |
+---------------+----------+----------+-------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Attention&lt;/strong&gt;: The table is copied once! It therefore needs twice the amount of disc space for a short time! This can be observed while the &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; command is running:&lt;/p&gt;
&lt;p&gt;MariaDB:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ watch -d -n 1 &amp;#39;ls -l trac* \#*&amp;#39;
-rw-rw---- 1 mysql mysql 1206 Feb 7 10:39 &amp;#39;#sql-alter-d57-8c.frm&amp;#39;
-rw-rw---- 1 mysql mysql 968884224 Feb 7 10:39 &amp;#39;#sql-alter-d57-8c.ibd&amp;#39;
-rw-rw---- 1 mysql mysql 1206 Feb 7 10:28 tracking.frm
-rw-rw---- 1 mysql mysql 1933574144 Feb 7 10:32 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;MySQL:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ watch -d -n 1 &amp;#39;ls -l trac* \#*&amp;#39;
-rw-r----- 1 mysql mysql 369098752 Feb 7 10:40 #sql-ib1594-4164062678.ibd
-rw-r----- 1 mysql mysql 1929379840 Feb 7 10:33 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The result is amazing! With MariaDB, the table has remained somewhat the same size:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-rw-rw---- 1 mysql mysql 1206 Feb 7 10:39 tracking.frm
-rw-rw---- 1 mysql mysql 1912602624 Feb 7 10:39 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With MySQL, on the other hand, the table has actually grown after the ‘defragmentation’, namely by approx. 14%:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-rw-r----- 1 mysql mysql 2197815296 Feb 7 10:41 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we execute the &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; command again, the size remains constant for both MariaDB and MySQL:&lt;/p&gt;
&lt;p&gt;MariaDB:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-rw-rw---- 1 mysql mysql 1206 Feb 7 10:46 tracking.frm
-rw-rw---- 1 mysql mysql 1912602624 Feb 7 10:48 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;MySQL:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-rw-r----- 1 mysql mysql 2197815296 Feb 7 10:48 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="attempt-1-null-out"&gt;Attempt 1: &lt;code&gt;NULL&lt;/code&gt; out&lt;/h3&gt;
&lt;p&gt;Now we &lt;code&gt;NULL&lt;/code&gt; out the values:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;SQL&amp;gt; UPDATE tracking
SET d0 = NULL, d1 = NULL, d2 = NULL, d3 = NULL, d4 = NULL
 , d5 = NULL, d6 = NULL, d7 = NULL, d8 = NULL, d9 = NULL
;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After this step, the sizes of the files have even grown slightly:&lt;/p&gt;
&lt;p&gt;MariaDB (+1.3%):&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-rw-rw---- 1 mysql mysql 1206 Feb 7 10:49 tracking.frm
-rw-rw---- 1 mysql mysql 1937768448 Feb 7 11:04 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;MySQL (+0.2%):&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-rw-r----- 1 mysql mysql 2202009600 Feb 7 11:04 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We then defragment the table again with the &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; command. The tables shrink as expected.&lt;/p&gt;
&lt;p&gt;MariaDB (to 23%):&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-rw-rw---- 1 mysql mysql 1206 Feb 7 11:09 tracking.frm
-rw-rw---- 1 mysql mysql 448790528 Feb 7 11:10 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;MySQL (to 24%):&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-rw-r----- 1 mysql mysql 520093696 Feb 7 11:10 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; again does NOT change the file size any more&amp;hellip;&lt;/p&gt;
&lt;h3 id="attempt-2-deleting-the-columns"&gt;Attempt 2: Deleting the columns&lt;/h3&gt;
&lt;p&gt;Now we try the whole thing again with the &lt;code&gt;DROP COLUMN&lt;/code&gt; command. The starting position is again the same as described above:&lt;/p&gt;
&lt;p&gt;MariaDB:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-rw-rw---- 1 mysql mysql 1206 Feb 7 11:15 tracking.frm
-rw-rw---- 1 mysql mysql 1933574144 Feb 7 11:18 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;MySQL:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-rw-r----- 1 mysql mysql 1929379840 Feb 7 11:19 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After the &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; command, the values look similar to the first attempt:&lt;/p&gt;
&lt;p&gt;MariaDB:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-rw-rw---- 1 mysql mysql 1206 Feb 7 11:20 tracking.frm
-rw-rw---- 1 mysql mysql 1912602624 Feb 7 11:21 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;MySQL:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-rw-r----- 1 mysql mysql 2197815296 Feb 7 11:21 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; again also brings no further changes, as above:&lt;/p&gt;
&lt;p&gt;MariaDB:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-rw-rw---- 1 mysql mysql 1206 Feb 7 11:22 tracking.frm
-rw-rw---- 1 mysql mysql 1912602624 Feb 7 11:23 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;MySQL:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-rw-r----- 1 mysql mysql 2197815296 Feb 7 11:24 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And now the actual second attempt with dropping the columns:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;SQL&amp;gt; ALTER TABLE tracking
 DROP COLUMN d0, DROP COLUMN d1, DROP COLUMN d2, DROP COLUMN d3, DROP COLUMN d4
, DROP COLUMN d5, DROP COLUMN d6, DROP COLUMN d7, DROP COLUMN d8, DROP COLUMN d9
;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first thing we notice is that the command is &lt;code&gt;INSTANTANEOUS&lt;/code&gt;, i.e. it does not make any changes to the data but only changes the metadata. On the one hand, this is good, as it minimises the impact on the application. On the other hand, it also means that no space is saved.&lt;/p&gt;
&lt;p&gt;So let&amp;rsquo;s get to grips with the whole thing again with the &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; command:&lt;/p&gt;
&lt;p&gt;MariaDB (to 93%):&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-rw-rw---- 1 mysql mysql 925 Feb 7 11:28 tracking.frm
-rw-rw---- 1 mysql mysql 415236096 Feb 7 11:29 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;MySQL (to 92%):&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-rw-r----- 1 mysql mysql 478150656 Feb 7 11:28 tracking.ibd
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="conclusion"&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Both, dropping the columns and the &lt;code&gt;NULL&lt;/code&gt; out of columns save a significant amount of space. Dropping the columns saves about 7% more space than &lt;code&gt;NULL&lt;/code&gt; them out. If it is possible from an application point of view, you should therefore drop columns that are no longer required, or if not possible, at least &lt;code&gt;NULL&lt;/code&gt; them out.&lt;/p&gt;
&lt;h2 id="experiment-with-postgresql"&gt;Experiment with PostgreSQL&lt;/h2&gt;
&lt;p&gt;And now let&amp;rsquo;s take a look at the whole thing with PostgreSQL 19devel.&lt;/p&gt;
&lt;h3 id="test-setup-1"&gt;Test setup&lt;/h3&gt;
&lt;p&gt;The test setup is analogous to MariaDB/MySQL:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;postgres=# -- DROP TABLE IF EXISTS tracking;

postgres=# CREATE TABLE tracking (
 id SERIAL PRIMARY KEY
, d0 DOUBLE PRECISION, d1 DOUBLE PRECISION, d2 DOUBLE PRECISION, d3 DOUBLE PRECISION, d4 DOUBLE PRECISION
, d5 DOUBLE PRECISION, d6 DOUBLE PRECISION, d7 DOUBLE PRECISION, d8 DOUBLE PRECISION, d9 DOUBLE PRECISION
);

postgres=# \timing

postgres=# INSERT INTO tracking (d0, d1, d2, d3, d4, d5, d6, d7, d8, d9)
 SELECT 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0;
postgres=# INSERT INTO tracking (d0, d1, d2, d3, d4, d5, d6, d7, d8, d9)
 SELECT 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 FROM tracking;
... bis 16 M rows
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Firstly, we want to know how big the table has actually become. PostgreSQL seems to know this information very precisely:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;postgres=# SELECT pg_relation_size(&amp;#39;tracking&amp;#39;) AS tab_siz
 , pg_size_pretty(pg_relation_size(&amp;#39;tracking&amp;#39;)) AS tab_siz_prtty
 , pg_indexes_size(&amp;#39;tracking&amp;#39;) AS idx_siz
 , pg_size_pretty(pg_indexes_size(&amp;#39;tracking&amp;#39;)) AS idx_siz_prtty
 , pg_relation_size(&amp;#39;tracking&amp;#39;) + pg_indexes_size(&amp;#39;tracking&amp;#39;) AS tab_and_idx_siz
 , pg_size_pretty(pg_relation_size(&amp;#39;tracking&amp;#39;) + pg_indexes_size(&amp;#39;tracking&amp;#39;)) AS tab_and_idx_siz_prtty
 , pg_total_relation_size(&amp;#39;tracking&amp;#39;) AS tot_rel_siz
 , pg_size_pretty(pg_total_relation_size(&amp;#39;tracking&amp;#39;)) AS tot_rel_siz_prtty
;
 tab_siz | tab_siz_prtty | idx_siz | idx_siz_prtty | tab_and_idx_siz | tab_and_idx_siz_prtty | tot_rel_siz | tot_rel_siz_prtty
------------+---------------+-----------+---------------+-----------------+-----------------------+-------------+-------------------
 1963417600 | 1872 MB | 376856576 | 359 MB | 2340274176 | 2232 MB | 2340798464 | 2232 MB
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then we want to know where these files can be found in the file system:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;postgres=# SELECT oid AS db_oid FROM pg_database WHERE datname = current_database();
 db_oid
--------
 5

postgres=# SELECT oid AS table_oid, relname, relnamespace, relfilenode
 FROM pg_class WHERE relname = &amp;#39;tracking&amp;#39;;
 table_oid | relname | relnamespace | relfilenode
-----------+----------+--------------+-------------
 40965 | tracking | 2200 | 40965

postgres=# SELECT i.indexrelid::regclass as index_name, i.indexrelid as index_oid
 FROM pg_index i
 JOIN pg_class c ON i.indrelid = c.oid
 WHERE c.relname = &amp;#39;tracking&amp;#39;;
 index_name | index_oid
---------------+-----------
 tracking_pkey | 40970

postgres=# SELECT pg_relation_filepath(&amp;#39;tracking&amp;#39;);
 pg_relation_filepath
----------------------
 base/5/40965
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Table and index size in the file system:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ ls -ltr 40965* 40970*
-rw------- 1 mysql mysql 40960 Feb 7 18:33 40965_vm
-rw------- 1 mysql mysql 499712 Feb 7 18:33 40965_fsm
-rw------- 1 mysql mysql 889675776 Feb 7 18:34 40965.1
-rw------- 1 mysql mysql 1073741824 Feb 7 18:34 40965
-rw------- 1 mysql mysql 376856576 Feb 7 18:35 40970
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*_fsm&lt;/code&gt; means &amp;ldquo;free space map&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*_vm&lt;/code&gt; means &amp;ldquo;visibility map&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*.1&lt;/code&gt; means 2nd segment of the object (table or index)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PostgreSQL seems to work with segments of 1 Gbyte by default and, unlike MariaDB/MySQL (&lt;code&gt;INFORMATION_SCHEMA&lt;/code&gt;), knows exactly how large its files are. And the discrepancy from above (between &lt;code&gt;tot_rel_siz&lt;/code&gt; and &lt;code&gt;tab_and_idx_siz&lt;/code&gt;) can be explained by the &lt;code&gt;fsm&lt;/code&gt; and &lt;code&gt;vm&lt;/code&gt; files.&lt;/p&gt;
&lt;p&gt;The PostgreSQL equivalent of the MariaDB/MySQL &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; is the &lt;code&gt;VACUUM FULL&lt;/code&gt; command:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;postgres=# VACUUM FULL tracking;

$ ls -ltr
-rw------- 1 mysql mysql 40960 Feb 7 18:39 40965_vm
-rw------- 1 mysql mysql 499712 Feb 7 18:39 40965_fsm
-rw------- 1 mysql mysql 1073741824 Feb 7 18:39 40965
-rw------- 1 mysql mysql 889675776 Feb 7 18:39 40965.1
-rw------- 1 mysql mysql 1073741824 Feb 7 18:39 40972
-rw------- 1 mysql mysql 889675776 Feb 7 18:39 40972.1
-rw------- 1 mysql mysql 0 Feb 7 18:39 40975

...

-rw------- 1 mysql mysql 49152 Feb 7 18:39 2704
-rw------- 1 mysql mysql 32768 Feb 7 18:39 2703
-rw------- 1 mysql mysql 32768 Feb 7 18:39 2696
-rw------- 1 mysql mysql 65536 Feb 7 18:39 2674
-rw------- 1 mysql mysql 81920 Feb 7 18:39 2673
-rw------- 1 mysql mysql 98304 Feb 7 18:39 2659
-rw------- 1 mysql mysql 139264 Feb 7 18:39 2658
-rw------- 1 mysql mysql 24576 Feb 7 18:39 2619_fsm
-rw------- 1 mysql mysql 163840 Feb 7 18:39 2619
-rw------- 1 mysql mysql 106496 Feb 7 18:39 2608
-rw------- 1 mysql mysql 491520 Feb 7 18:39 1249
-rw------- 1 mysql mysql 122880 Feb 7 18:39 1247
-rw------- 1 mysql mysql 32768 Feb 7 18:39 2662
-rw------- 1 mysql mysql 114688 Feb 7 18:39 1259
-rw------- 1 mysql mysql 16384 Feb 7 18:39 3455
-rw------- 1 mysql mysql 49152 Feb 7 18:39 2663
-rw------- 1 mysql mysql 1073741824 Feb 7 18:39 40972
-rw------- 1 mysql mysql 889675776 Feb 7 18:39 40972.1
-rw------- 1 mysql mysql 376864768 Feb 7 18:39 40975
-rw------- 1 mysql mysql 0 Feb 7 18:39 40965
-rw------- 1 mysql mysql 0 Feb 7 18:39 40970
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The first thing you notice is that PostgreSQL touches quite a few files and the ‘free space map’ file has disappeared. In contrast to MariaDB/MySQL, the table segments have remained the same size. You can also see that the old table has ‘disappeared’ (40965, 40970) and a new one has been created (40972 and 40975). The &lt;code&gt;VACUUM FULL&lt;/code&gt; command in PostgreSQL also creates a copy of the data, as in MariaDB/MySQL.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;postgres=# SELECT pg_relation_size(&amp;#39;tracking&amp;#39;) AS tab_siz
 , pg_size_pretty(pg_relation_size(&amp;#39;tracking&amp;#39;)) AS tab_siz_prtty
 , pg_indexes_size(&amp;#39;tracking&amp;#39;) AS idx_siz
 , pg_size_pretty(pg_indexes_size(&amp;#39;tracking&amp;#39;)) AS idx_siz_prtty
 , pg_relation_size(&amp;#39;tracking&amp;#39;) + pg_indexes_size(&amp;#39;tracking&amp;#39;) AS tab_and_idx_siz
 , pg_size_pretty(pg_relation_size(&amp;#39;tracking&amp;#39;) + pg_indexes_size(&amp;#39;tracking&amp;#39;)) AS tab_and_idx_siz_prtty
 , pg_total_relation_size(&amp;#39;tracking&amp;#39;) AS tot_rel_siz
 , pg_size_pretty(pg_total_relation_size(&amp;#39;tracking&amp;#39;)) AS tot_rel_siz_prtty
;
 tab_siz | tab_siz_prtty | idx_siz | idx_siz_prtty | tab_and_idx_siz | tab_and_idx_siz_prtty | tot_rel_siz | tot_rel_siz_prtty
------------+---------------+-----------+---------------+-----------------+-----------------------+-------------+-------------------
 1963417600 | 1872 MB | 376864768 | 359 MB | 2340282368 | 2232 MB | 2340282368 | 2232 MB
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The following query helps to understand which other files/objects have been created:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;postgres=# SELECT c.oid, c.relname, ns.nspname
FROM pg_class AS c
JOIN pg_namespace AS ns ON ns.oid = c.relnamespace
WHERE c.oid IN (2704, 2703, 2696, 2674, 2673, 2659, 2658, 2619, 2608, 1249, 1247, 40972, 2662, 1259, 3455, 2663, 40975, 40965, 40970)
;
 oid | relname | nspname
-------+-----------------------------------+------------
 40965 | tracking | public
 40970 | tracking_pkey | public
 2619 | pg_statistic | pg_catalog
 1247 | pg_type | pg_catalog
 2703 | pg_type_oid_index | pg_catalog
 2704 | pg_type_typname_nsp_index | pg_catalog
 2658 | pg_attribute_relid_attnam_index | pg_catalog
 2659 | pg_attribute_relid_attnum_index | pg_catalog
 2662 | pg_class_oid_index | pg_catalog
 2663 | pg_class_relname_nsp_index | pg_catalog
 3455 | pg_class_tblspc_relfilenode_index | pg_catalog
 2696 | pg_statistic_relid_att_inh_index | pg_catalog
 2673 | pg_depend_depender_index | pg_catalog
 2674 | pg_depend_reference_index | pg_catalog
 1249 | pg_attribute | pg_catalog
 1259 | pg_class | pg_catalog
 2608 | pg_depend | pg_catalog

postgres=# SELECT i.indexrelid::regclass as index_name, i.indexrelid as index_oid, ns.nspname
 FROM pg_index i
 JOIN pg_class c ON i.indrelid = c.oid
 JOIN pg_namespace AS ns ON ns.oid = c.relnamespace
 WHERE c.oid IN (2704, 2703, 2696, 2674, 2673, 2659, 2658, 2619, 2608, 1249, 1247, 40972, 2662, 1259, 3455, 2663, 40975, 40965, 40970)
;
 index_name | index_oid | nspname
-----------------------------------+-----------+------------
 pg_type_typname_nsp_index | 2704 | pg_catalog
 pg_attribute_relid_attnam_index | 2658 | pg_catalog
 tracking_pkey | 40970 | public
 pg_class_relname_nsp_index | 2663 | pg_catalog
 pg_class_tblspc_relfilenode_index | 3455 | pg_catalog
 pg_type_oid_index | 2703 | pg_catalog
 pg_attribute_relid_attnum_index | 2659 | pg_catalog
 pg_statistic_relid_att_inh_index | 2696 | pg_catalog
 pg_depend_depender_index | 2673 | pg_catalog
 pg_depend_reference_index | 2674 | pg_catalog
 pg_class_oid_index | 2662 | pg_catalog
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="attempt-1-null-out-1"&gt;Attempt 1: &lt;code&gt;NULL&lt;/code&gt; out&lt;/h3&gt;
&lt;p&gt;Then we also &lt;code&gt;NULL&lt;/code&gt; the columns in PostgreSQL. From here on, we save the view of the file system, as PostgreSQL seems to know the file sizes exactly, as we have seen above:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;postgres=# UPDATE tracking
SET d0 = NULL, d1 = NULL, d2 = NULL, d3 = NULL, d4 = NULL
 , d5 = NULL, d6 = NULL, d7 = NULL, d8 = NULL, d9 = NULL
;

postgres=# SELECT pg_relation_size(&amp;#39;tracking&amp;#39;) AS tab_siz
 , pg_size_pretty(pg_relation_size(&amp;#39;tracking&amp;#39;)) AS tab_siz_prtty
 , pg_indexes_size(&amp;#39;tracking&amp;#39;) AS idx_siz
 , pg_size_pretty(pg_indexes_size(&amp;#39;tracking&amp;#39;)) AS idx_siz_prtty
 , pg_relation_size(&amp;#39;tracking&amp;#39;) + pg_indexes_size(&amp;#39;tracking&amp;#39;) AS tab_and_idx_siz
 , pg_size_pretty(pg_relation_size(&amp;#39;tracking&amp;#39;) + pg_indexes_size(&amp;#39;tracking&amp;#39;)) AS tab_and_idx_siz_prtty
 , pg_total_relation_size(&amp;#39;tracking&amp;#39;) AS tot_rel_siz
 , pg_size_pretty(pg_total_relation_size(&amp;#39;tracking&amp;#39;)) AS tot_rel_siz_prtty
;
 tab_siz | tab_siz_prtty | idx_siz | idx_siz_prtty | tab_and_idx_siz | tab_and_idx_siz_prtty | tot_rel_siz | tot_rel_siz_prtty
------------+---------------+-----------+---------------+-----------------+-----------------------+-------------+-------------------
 2695716864 | 2571 MB | 753696768 | 719 MB | 3449413632 | 3290 MB | 3450101760 | 3290 MB
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here we see that the table segments grow massively (+37%), which is called ‘bloat’ in PostgreSQL terminology. The MVCC implementation of PostgreSQL stores both the old and never new version of the row ‘in-place’ directly in the table, in contrast to MariaDB/MySQL which stores the old version in UNDO space and the new row ‘in-place’. The index file also increases significantly (+100%). We need to do more research to find out why this is the case. In addition, a ‘free space map’ is created again (difference between &lt;code&gt;tot_rel_siz&lt;/code&gt; and &lt;code&gt;tab_and_idx_siz&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;A subsequent &lt;code&gt;VACUUM FULL&lt;/code&gt; reduces the table (to 28%) and the index (to 50%) again in relation to the previous size:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;postgres=# VACUUM FULL tracking;

postgres=# SELECT pg_relation_size(&amp;#39;tracking&amp;#39;) AS tab_siz
 , pg_size_pretty(pg_relation_size(&amp;#39;tracking&amp;#39;)) AS tab_siz_prtty
 , pg_indexes_size(&amp;#39;tracking&amp;#39;) AS idx_siz
 , pg_size_pretty(pg_indexes_size(&amp;#39;tracking&amp;#39;)) AS idx_siz_prtty
 , pg_relation_size(&amp;#39;tracking&amp;#39;) + pg_indexes_size(&amp;#39;tracking&amp;#39;) AS tab_and_idx_siz
 , pg_size_pretty(pg_relation_size(&amp;#39;tracking&amp;#39;) + pg_indexes_size(&amp;#39;tracking&amp;#39;)) AS tab_and_idx_siz_prtty
 , pg_total_relation_size(&amp;#39;tracking&amp;#39;) AS tot_rel_siz
 , pg_size_pretty(pg_total_relation_size(&amp;#39;tracking&amp;#39;)) AS tot_rel_siz_prtty
;
 tab_siz | tab_siz_prtty | idx_siz | idx_siz_prtty | tab_and_idx_siz | tab_and_idx_siz_prtty | tot_rel_siz | tot_rel_siz_prtty
-----------+---------------+-----------+---------------+-----------------+-----------------------+-------------+-------------------
 742916096 | 709 MB | 376864768 | 359 MB | 1119780864 | 1068 MB | 1119780864 | 1068 MB
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and also in relation to the original size, the table (to 38%) and the index (to 100%) become smaller again. Why the index has remained the same size and only the table has shrunk remains to be investigated&amp;hellip;&lt;/p&gt;
&lt;h3 id="experiment-2-deleting-the-columns"&gt;Experiment 2: Deleting the columns&lt;/h3&gt;
&lt;p&gt;The columns are then dropped with &lt;code&gt;DROP COLUMN&lt;/code&gt;.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;postgres=# ALTER TABLE tracking
 DROP COLUMN d0, DROP COLUMN d1, DROP COLUMN d2, DROP COLUMN d3, DROP COLUMN d4
, DROP COLUMN d5, DROP COLUMN d6, DROP COLUMN d7, DROP COLUMN d8, DROP COLUMN d9
;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As the response was immediate, it can be assumed that this operation is also instantaneous. Unfortunately, I couldn&amp;rsquo;t find anything about this in the PostgreSQL documentation.&lt;/p&gt;
&lt;p&gt;Nothing has changed significantly in terms of size, which is actually to be expected with an instant operation. However, the fact that the size did not change after the &lt;code&gt;VACUUM FULL&lt;/code&gt; command was a little surprising:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; tab_siz | tab_siz_prtty | idx_siz | idx_siz_prtty | tab_and_idx_siz | tab_and_idx_siz_prtty | tot_rel_siz | tot_rel_siz_prtty
-----------+---------------+-----------+---------------+-----------------+-----------------------+-------------+-------------------
 742916096 | 709 MB | 376864768 | 359 MB | 1119780864 | 1068 MB | 1120010240 | 1068 MB

postgres=# VACUUM FULL tracking;

 tab_siz | tab_siz_prtty | idx_siz | idx_siz_prtty | tab_and_idx_siz | tab_and_idx_siz_prtty | tot_rel_siz | tot_rel_siz_prtty
-----------+---------------+-----------+---------------+-----------------+-----------------------+-------------+-------------------
 742916096 | 709 MB | 376864768 | 359 MB | 1119780864 | 1068 MB | 1119780864 | 1068 MB
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="remarks"&gt;Remarks&lt;/h2&gt;
&lt;p&gt;Locking in PostgreSQL works as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;VACUUM&lt;/code&gt; Concurrent DML commands are possible similar to the MariaDB/MySQL &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; command. However, the result is not quite the same.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VACUUM FULL&lt;/code&gt; causes an &lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt; lock. Similar to the MariaDB/MySQL 5.5 and older &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; command. DML and &lt;code&gt;SELECT&lt;/code&gt; commands are NOT permitted.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sources"&gt;Sources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://neon.com/postgresql/postgresql-administration/postgresql-database-indexes-table-size" target="_blank"&gt;How to Get Sizes of Database Objects in PostgreSQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.postgresql.org/docs/current/storage-file-layout.html" target="_blank"&gt;Database File Layout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.postgresql.org/docs/current/functions-admin.html" target="_blank"&gt;System Administration Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.postgresql.org/docs/current/sql-cluster.html" target="_blank"&gt;CLUSTER&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.postgresql.org/docs/current/sql-vacuum.html" target="_blank"&gt;VACUUM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.postgresql.org/docs/current/explicit-locking.html" target="_blank"&gt;Explicit Locking&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="additional-attempts"&gt;Additional attempts&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Instead of &lt;code&gt;0.0&lt;/code&gt;, &lt;code&gt;NULL&lt;/code&gt; was filled into the columns &lt;code&gt;d0&lt;/code&gt; - &lt;code&gt;d9&lt;/code&gt;. The table remained small (&lt;code&gt;tot_rel_siz_prtty = 1068 MB&lt;/code&gt;). It is therefore also worth saving &lt;code&gt;NULL&lt;/code&gt; instead of dummy values with PostgreSQL.&lt;/li&gt;
&lt;li&gt;The columns &lt;code&gt;d0&lt;/code&gt; - &lt;code&gt;d9&lt;/code&gt; were created with &lt;code&gt;DOUBLE PRECISION NOT NULL&lt;/code&gt; and the values &lt;code&gt;0.0&lt;/code&gt; were filled. No effect: The table remained large (&lt;code&gt;tot_rel_siz_prtty = 2232 MB&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This page was translated using &lt;a href="https://www.deepl.com/en/translator" target="_blank"&gt;deepl.com&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Someone is deleting my shared memory segments!</title><link>https://www.fromdual.com/blog/deleted-postgresql-shared-memory-segments/</link><pubDate>Sun, 08 Feb 2026 06:27:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/deleted-postgresql-shared-memory-segments/</guid><description>&lt;p&gt;When we work with PostgreSQL under our &lt;a href="https://www.fromdual.com/myenv/"&gt;myEnv&lt;/a&gt;, we regularly get shared memory segment errors. Example:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;psql: error: connection to server on socket &amp;#34;/tmp/.s.PGSQL.5433&amp;#34; failed:
FATAL: could not open shared memory segment &amp;#34;/PostgreSQL.4220847662&amp;#34;:
No such file or directory
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;or we see similar messages in the PostgreSQL error log:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ERROR: could not open shared memory segment &amp;#34;/PostgreSQL.4220847662&amp;#34;:
No such file or directory
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Because I am a MariaDB/MySQL admin, I am not very familiar with shared memory problems (MariaDB/MySQL does not work with shared memory). Fortunately, a search on the Internet led us on the right track (&lt;a href="https://www.postgresql.org/message-id/56A52018.1030001%40gmx.net" target="_blank" title="Re: systemd deletes shared memory segment in /dev/shm/Postgresql.NNNNNN"&gt;source&lt;/a&gt;). It is noted there:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The documentation of systemd states that this only happens for
non-system users. Can you check whether your &amp;ldquo;postgres&amp;rdquo; user (or
whatever you are using) is a system user?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="linux-system-user"&gt;Linux System User&lt;/h2&gt;
&lt;p&gt;First I had to find out what a system user under Linux actually is. I found an answer here: &lt;a href="https://unix.stackexchange.com/questions/80277/whats-the-difference-between-a-normal-user-and-a-system-user" target="_blank"&gt;What&amp;rsquo;s the difference between a normal user and a system user?&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;That is not a technical difference but an organizational decision. E.g. it makes sense to show normal users in a login dialog (so that you can click them instead of having to type the user name) but it wouldn&amp;rsquo;t to show system accounts (the UIDs under which daemons and other automatic processes run) there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The LSB standard says: &lt;a href="https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/uidrange.html" target="_blank"&gt;User ID Ranges&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The system User IDs from 0 to 99 should be statically allocated by the system, and shall not be created by applications.&lt;br&gt;
The system User IDs from 100 to 499 should be reserved for dynamic allocation by system administrators and post install scripts using useradd.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;On my Ubuntu system it looks like this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ grep SYS_ /etc/login.defs
#SYS_UID_MIN 100
#SYS_UID_MAX 999
#SYS_GID_MIN 100
#SYS_GID_MAX 999
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This would be correct for the PostgreSQL user:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ id postgres
uid=130(postgres) gid=142(postgres) groups=142(postgres),116(ssl-cert)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But since the PostgreSQL instance in question runs under our &lt;a href="https://www.fromdual.com/myenv/"&gt;myEnv&lt;/a&gt;, that&amp;rsquo;s different:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ id dba
uid=1001(dba) gid=1001(dba) groups=1001(dba)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So now we have two options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We change &lt;code&gt;SYS_UID_MAX&lt;/code&gt; and &lt;code&gt;SYS_GID_MAX&lt;/code&gt; to 1001 (simple variant).&lt;/li&gt;
&lt;li&gt;Or we change the &lt;code&gt;UID&lt;/code&gt; and the &lt;code&gt;GID&lt;/code&gt; of our user &lt;code&gt;dba&lt;/code&gt; to less than 1000.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="simple-variant-change-sys_uid_max-and-sys_gid_max-to-1001"&gt;Simple variant: Change &lt;code&gt;SYS_UID_MAX&lt;/code&gt; and &lt;code&gt;SYS_GID_MAX&lt;/code&gt; to 1001&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# /etc/login.defs
SYS_UID_MAX 1001
SYS_GID_MAX 1001
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To be on the safe side, the machine was rebooted. But that did not help: After a short time, the same errors occur again.&lt;/p&gt;
&lt;h2 id="more-complicated-variant-changing-the-uid-from-1001-to-990"&gt;More complicated variant: Changing the &lt;code&gt;UID&lt;/code&gt; from 1001 to 990&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ cat /etc/passwd
...
polkitd:x:997:997:User for polkitd:/:/usr/sbin/nologin
systemd-coredump:x:998:998:systemd Core Dumper:/:/usr/sbin/nologin
tomcat:x:999:999:Apache Tomcat:/:/sbin/nologin
oli:x:1000:1000:Oli Sennhauser,,,:/home/oli:/bin/bash
dba:x:1001:1001:DBA user:/home/dba:/bin/bash
...

$ id dba
uid=1001(dba) gid=1001(dba) groups=1001(dba)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To do this, all processes of this user must be stopped!&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ usermod --uid 990 dba
$ groupmod --gid 990 dba

$ find / -user 1001 -exec chown --no-dereference dba {} \;
$ find / -group 1001 -exec chgrp --no-dereference dba {} \;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This seems to have solved the problem!&lt;/p&gt;
&lt;h2 id="additional-information"&gt;Additional information&lt;/h2&gt;
&lt;p&gt;A source mentioned above also recommended setting the following parameters in &lt;code&gt;systemd-logind&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# /etc/systemd/system/systemd-logind.service.d/override.conf
RemoveIPC=no
RuntimeDirectorySize=1%
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;However, this measure is no longer necessary as it works without this change.&lt;/p&gt;
&lt;p&gt;This page was translated using &lt;a href="https://www.deepl.com/en/translator" target="_blank"&gt;deepl.com&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>FromDual Backup and Recovery Manager</title><link>https://www.fromdual.com/software/fromdual-backup-and-recovery-manager/</link><pubDate>Sat, 07 Feb 2026 20:17:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/software/fromdual-backup-and-recovery-manager/</guid><description>&lt;p&gt;Coming soon&amp;hellip;&lt;/p&gt;
&lt;p&gt;Have also a look at the &lt;a href="https://support.fromdual.com/documentation/brman/brman.html" target="_blank"&gt;Backup and Recovery Manager Documentation&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Load CSV files into the database</title><link>https://www.fromdual.com/blog/load-csv-files-into-the-database/</link><pubDate>Fri, 06 Feb 2026 18:04:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/load-csv-files-into-the-database/</guid><description>&lt;p&gt;Recently, I wanted to display the places of residence of the members of my club on a map for a personal gimmick (&lt;a href="https://www.shinguz.ch/computer/gis/igoc-mitglieder/" target="_blank"&gt;IGOC members&lt;/a&gt;). I knew the addresses of the club members. But not the coordinates of their places of residence.&lt;/p&gt;
&lt;p&gt;So I went in search of the coordinates and found what I was looking for at the Federal Office of Topography (&lt;a href="https://www.swisstopo.admin.ch/en" target="_blank"&gt;swisstopo&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The data is available there as a CSV file. Details here: &lt;a href="https://www.shinguz.ch/computer/gis/schweizer-ortschafts-koordinaten/" target="_blank"&gt;Swiss town coordinates&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;How do I load this data into a database?&lt;/p&gt;
&lt;h2 id="loading-the-data-with-mariadbmysql"&gt;Loading the data with MariaDB/MySQL&lt;/h2&gt;
&lt;p&gt;MariaDB and MySQL have the &lt;code&gt;LOAD DATA INFILE&lt;/code&gt; command:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;SQL&amp;gt; DROP TABLE IF EXISTS wgs84;

SQL&amp;gt; -- SET GLOBAL local_infile = ON; -- Only needed with MySQL

SQL&amp;gt; CREATE TABLE wgs84 (
 ortschaftsname VARCHAR(32)
, plz4 SMALLINT
, zusatzziffer SMALLINT
, zip_id SMALLINT UNSIGNED
, gemeindename VARCHAR(32)
, bfs_nr SMALLINT
, kantonskuerzel CHAR(2)
, adressenanteil varchar(8)
, e DOUBLE
, n DOUBLE
, sprache VARCHAR(8)
, validity VARCHAR(12)
);

SQL&amp;gt; -- TRUNCATE TABLE wgs84;

SQL&amp;gt; LOAD DATA LOCAL INFILE &amp;#39;/tmp/AMTOVZ_CSV_WGS84/AMTOVZ_CSV_WGS84.csv&amp;#39;
INTO TABLE wgs84
FIELDS TERMINATED BY &amp;#39;;&amp;#39;
LINES TERMINATED BY &amp;#39;\r\n&amp;#39;
IGNORE 1 LINES
;
Query OK, 5713 rows affected
Records: 5713 Deleted: 0 Skipped: 0 Warnings: 0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can then query the data in the database:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;SQL&amp;gt; SELECT * FROM wgs84 ORDER BY ortschaftsname LIMIT 5;
+----------------+------+--------------+--------+--------------+--------+----------------+----------------+-------------------+--------------------+---------+------------+
| ortschaftsname | plz4 | zusatzziffer | zip_id | gemeindename | bfs_nr | kantonskuerzel | adressenanteil | e | n | sprache | validity |
+----------------+------+--------------+--------+--------------+--------+----------------+----------------+-------------------+--------------------+---------+------------+
| Aadorf | 8355 | 0 | 4672 | Aadorf | 4551 | TG | 96.802 % | 8.903193007810433 | 47.491079014637265 | de | 2008-07-01 |
| Aadorf | 8355 | 0 | 4672 | Elgg | 294 | ZH | 3.198 % | 8.89206766645808 | 47.4933781685032 | de | 2008-07-01 |
| Aarau | 5000 | 0 | 2913 | Aarau | 4001 | AG | 99.713 % | 8.048148371736266 | 47.38973523857376 | de | 2008-07-01 |
| Aarau | 5000 | 0 | 2913 | Suhr | 4012 | AG | 0.287 % | 8.059410934099922 | 47.383298214804334 | de | 2008-07-01 |
| Aarau | 5004 | 0 | 2932 | Aarau | 4001 | AG | 100 % | 8.060698546432551 | 47.400587704180744 | de | 2008-07-01 |
+----------------+------+--------------+--------+--------------+--------+----------------+----------------+-------------------+--------------------+---------+------------+
5 rows in set
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Or something more precise:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;SQL&amp;gt; SELECT ortschaftsname AS city, plz4 AS city_code, e AS lon, n AS lat
 FROM wgs84 WHERE plz4 IN (8280, 4663, 6043);
+-------------+-----------+-------------------+--------------------+
| city | city_code | lon | lat |
+-------------+-----------+-------------------+--------------------+
| Aarburg | 4663 | 7.904271716719409 | 47.321443418782955 |
| Aarburg | 4663 | 7.889249714098425 | 47.313536073562474 |
| Aarburg | 4663 | 7.880309179095798 | 47.31255194439023 |
| Adligenswil | 6043 | 8.364849060491428 | 47.07037816052481 |
| Kreuzlingen | 8280 | 9.173740257895282 | 47.64491046067056 |
| Kreuzlingen | 8280 | 9.159171428030783 | 47.654149879509134 |
| Kreuzlingen | 8280 | 9.204470741840725 | 47.639949130372145 |
+-------------+-----------+-------------------+--------------------+
7 rows in set (0.003 sec)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I will leave it to the reader to clean out the duplicates&amp;hellip; :-)&lt;/p&gt;
&lt;p&gt;So far so good, now to the finer points::&lt;/p&gt;
&lt;h3 id="differences-between-mariadb-and-mysql"&gt;Differences between MariaDB and MySQL&lt;/h3&gt;
&lt;p&gt;The procedure described above works perfectly with MariaDB 11.4 and 11.8. There are small differences with MySQL 8.4:&lt;/p&gt;
&lt;p&gt;The first error message that prevents loading is this one:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ERROR 3948 (42000): Loading local data is disabled; this must be enabled on both the client and server sides
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It can be bypassed relatively easily with the command:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;SQL&amp;gt; SET GLOBAL local_infile = ON;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The next attempt will fail as follows:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ERROR 2068 (HY000): LOAD DATA LOCAL INFILE file request rejected due to restrictions on access.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This problem can be solved by starting the MySQL client as follows:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ mysql --local-infile=1 --user=root test
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="sources"&gt;Sources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;MariaDB: &lt;a href="https://mariadb.com/docs/server/reference/sql-statements/data-manipulation/inserting-loading-data/load-data-into-tables-or-index/load-data-infile" target="_blank"&gt;LOAD DATA INFILE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MySQL: &lt;a href="https://dev.mysql.com/doc/refman/8.4/en/load-data.html" target="_blank"&gt;LOAD DATA Statement&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="loading-the-data-with-postgresql"&gt;Loading the data with PostgreSQL&lt;/h2&gt;
&lt;p&gt;PostgreSQL has the command &lt;code&gt;COPY ... FROM&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;postgres=# DROP TABLE IF EXISTS wgs84;

postgres=# CREATE TABLE wgs84 (
 ortschaftsname VARCHAR(32)
, plz4 SMALLINT
, zusatzziffer SMALLINT
, zip_id INT
, gemeindename VARCHAR(32)
, bfs_nr SMALLINT
, kantonskuerzel CHAR(2)
, adressenanteil varchar(8)
, e DOUBLE PRECISION
, n DOUBLE PRECISION
, sprache VARCHAR(8)
, validity VARCHAR(12)
);

postgres=# -- TRUNCATE TABLE wgs84;

postgres=# COPY wgs84
FROM &amp;#39;/tmp/AMTOVZ_CSV_WGS84/AMTOVZ_CSV_WGS84.csv&amp;#39;
DELIMITER &amp;#39;;&amp;#39;
CSV HEADER
;
COPY 5713
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here, too, we receive the result as expected in the usual PostgreSQL form:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;postgres=# SELECT ortschaftsname AS city, plz4 AS city_code, e AS lon, n AS lat
 FROM wgs84 WHERE plz4 IN (8280, 4663, 6043);
 city | city_code | lon | lat
-------------+-----------+-------------------+--------------------
 Aarburg | 4663 | 7.904271716719409 | 47.321443418782955
 Aarburg | 4663 | 7.889249714098425 | 47.313536073562474
 Aarburg | 4663 | 7.880309179095798 | 47.31255194439023
 Adligenswil | 6043 | 8.36487538940682 | 47.07037794822416
 Kreuzlingen | 8280 | 9.173740257895282 | 47.64491046067056
 Kreuzlingen | 8280 | 9.159171428030783 | 47.654149879509134
 Kreuzlingen | 8280 | 9.204470741840725 | 47.639949130372145
(7 rows)
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="sources-1"&gt;Sources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;PostgreSQL: &lt;a href="https://www.postgresql.org/docs/current/sql-copy.html" target="_blank"&gt;COPY&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="small-differences-between-mariadbmysql-and-postgresql"&gt;Small differences between MariaDB/MySQL and PostgreSQL&lt;/h2&gt;
&lt;p&gt;Basically, the load command is completely different in the two database worlds.&lt;/p&gt;
&lt;p&gt;With MariaDB and PostgreSQL, the commands run “out-of-the-box”. MySQL has two additional security hurdles built in here.&lt;/p&gt;
&lt;p&gt;PostgreSQL does not recognise &lt;code&gt;UNSIGNED&lt;/code&gt; integer data types, so the next largest data type (&lt;code&gt;INT&lt;/code&gt;) must be used, which is a little less space-saving than with MariaDB/MySQL.&lt;/p&gt;
&lt;h2 id="remarks"&gt;Remarks&lt;/h2&gt;
&lt;p&gt;When we did the same test a few days ago, there was still a loading error. So it seems that the data source has also changed slightly&amp;hellip;&lt;/p&gt;
&lt;p&gt;I have not found out quickly whether there is an SQL standard for these load commands and if so, whether MariaDB/MySQL or PostgreSQL are standard-compliant here.&lt;/p&gt;
&lt;p&gt;And of course there are other ways to get your CSV data into the database&amp;hellip;&lt;/p&gt;
&lt;p&gt;The tools &lt;code&gt;mariadb-import&lt;/code&gt;/&lt;code&gt;mysqlimport&lt;/code&gt; are used if you want to do this from the command line. The CSV Storage Engine can also be misused for this purpose (see &lt;a href="https://www.fromdual.com/blog/csv-storage-engine/"&gt;here&lt;/a&gt; for details). An officially supported variant is the MariaDB CONNECT Storage Engine with the CSV type (see &lt;a href="https://mariadb.com/docs/server/server-usage/storage-engines/connect/connect-table-types/connect-csv-and-fmt-table-types" target="_blank"&gt;here&lt;/a&gt;):&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;SQL&amp;gt; INSTALL SONAME &amp;#39;ha_connect&amp;#39;;

SQL&amp;gt; CREATE TABLE wgs84_fdw
ENGINE = CONNECT
table_type = CSV
file_name=&amp;#39;/tmp/AMTOVZ_CSV_WGS84/AMTOVZ_CSV_WGS84.csv&amp;#39;
header = 1
sep_char = &amp;#39;;&amp;#39;
quoted = 0;

SQL&amp;gt; INSERT INTO wgs84 SELECT * FROM wgs84_fdw;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Unfortunately, it looks like the CONNECT Storage Engine will no longer be supported by MariaDB! And the &lt;code&gt;mydumper&lt;/code&gt;/&lt;code&gt;myloader&lt;/code&gt; tool also seems to be able to handle CSV files.&lt;/p&gt;
&lt;p&gt;And of course the whole thing can also be solved using applications&amp;hellip;&lt;/p&gt;
&lt;p&gt;With PostgreSQL there are the following options:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;postgres=# \copy wgs84 FROM &amp;#39;/tmp/AMTOVZ_CSV_WGS84/AMTOVZ_CSV_WGS84.csv&amp;#39; DELIMITER &amp;#39;;&amp;#39; CSV HEADER
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;then from the shell:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ psql --user=dba -c &amp;#34;\copy wgs84 FROM &amp;#39;/tmp/AMTOVZ_CSV_WGS84/AMTOVZ_CSV_WGS84.csv&amp;#39; DELIMITER &amp;#39;;&amp;#39; CSV HEADER&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And the variant via the Foreign Data Wrapper (FWD). But I have not tried this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;postgres=# CREATE EXTENSION postgres_fdw;

postgres=# CREATE SERVER foreign_server
 FOREIGN DATA WRAPPER postgres_fdw
 OPTIONS (
 datasource &amp;#39;CSV:/tmp/AMTOVZ_CSV_WGS84/AMTOVZ_CSV_WGS84.csv&amp;#39;,
 format &amp;#39;CSV&amp;#39;
 )
;

postgres=# CREATE USER MAPPING FOR local_user
 SERVER foreign_server
 OPTIONS (user &amp;#39;foreign_user&amp;#39;, password &amp;#39;password&amp;#39;)
;

postgres=# CREATE FOREIGN TABLE foreign_table (
 id integer NOT NULL,
 data text
)
 SERVER foreign_server
 OPTIONS (schema_name &amp;#39;some_schema&amp;#39;, table_name &amp;#39;some_table&amp;#39;)
;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="addendum"&gt;Addendum&lt;/h2&gt;
&lt;p&gt;The MariaDB/MySQL data type &lt;code&gt;DOUBLE&lt;/code&gt; is called &lt;code&gt;DOUBLE PRECISION&lt;/code&gt; in ProsgreSQL.&lt;/p&gt;
&lt;p&gt;This page was translated using &lt;a href="https://www.deepl.com/en/translator" target="_blank"&gt;deepl.com&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>MariaDB/MySQL Environment MyEnv 2.1.1 has been released</title><link>https://www.fromdual.com/blog/myenv-release-notes/fromdual-environment-myenv-2.1.1-has-been-released/</link><pubDate>Fri, 12 Dec 2025 17:43:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/myenv-release-notes/fromdual-environment-myenv-2.1.1-has-been-released/</guid><description>&lt;p&gt;FromDual has the pleasure to announce the release of the new version 2.1.1 of its popular MariaDB, Galera Cluster and MySQL multi-instance environment &lt;a href="https://www.fromdual.com/software/fromdual-myenv/" title="MariaDB, MySQL and PostgreSQL multi-instance environment"&gt;MyEnv&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The new MyEnv can be downloaded &lt;a href="https://support.fromdual.com/admin/public/download.php" target="_blank" title="FromDual download"&gt;here&lt;/a&gt;. How to install MyEnv is described in the &lt;a href="https://support.fromdual.com/documentation/myenv/myenv.html" target="_blank"&gt;MyEnv Installation Guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the inconceivable case that you find a bug in MyEnv please report it to us by sending an &lt;a href="mailto:contact@fromdual.com?Subject=Bug report for myenv"&gt;email&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Any feedback, statements and testimonials are welcome as well! Please &lt;a href="mailto:feedback@fromdual.com?Subject=Feedback for fpmmm"&gt;send them to us&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="upgrade-from-11x-to-20"&gt;Upgrade from 1.1.x to 2.0&lt;/h2&gt;
&lt;p&gt;Please look at the &lt;a href="https://www.fromdual.com/mysql-mariadb-environment-myenv-2.0.0-has-been-released" title="MySQL Environment MyEnv 2.0.0 has been released"&gt;MyEnv 2.0.0 Release Notes&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="upgrade-from-20x-to-211"&gt;Upgrade from 2.0.x to 2.1.1&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ sudo -i -u mysql
$ cd ${HOME}/product
$ tar xf /download/myenv-2.1.1.tar.gz
$ rm -f myenv
$ ln -s myenv-2.1.1 myenv
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="plug-ins"&gt;Plug-ins&lt;/h3&gt;
&lt;p&gt;If you are using plug-ins for &lt;code&gt;showMyEnvStatus&lt;/code&gt; create all the links in the new directory structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cd ${HOME}/product/myenv
$ ln -s ../../utl/oem_agent.php plg/showMyEnvStatus/
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="upgrade-of-the-instance-directory-structure"&gt;Upgrade of the instance directory structure&lt;/h3&gt;
&lt;p&gt;From MyEnv 1.0 to 2.0 the directory structure of instances has fundamentally changed. Nevertheless MyEnv 2.0 works fine with MyEnv 1.0 directory structures.&lt;/p&gt;
&lt;h2 id="changes-in-myenv-211"&gt;Changes in MyEnv 2.1.1&lt;/h2&gt;
&lt;h3 id="myenv"&gt;MyEnv&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;addInstance&lt;/code&gt; for PostgreSQL added.&lt;/li&gt;
&lt;li&gt;Basic PostgreSQL functionality implemented.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;up&lt;/code&gt; working now.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stop&lt;/code&gt;, &lt;code&gt;start&lt;/code&gt;, &lt;code&gt;restart&lt;/code&gt; and &lt;code&gt;status&lt;/code&gt; implemented for PostgreSQL.&lt;/li&gt;
&lt;li&gt;Version extraction for PostgreSQL added.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;extractVersion&lt;/code&gt; rewritten so section config is passed and not &lt;code&gt;basedir&lt;/code&gt; any more.&lt;/li&gt;
&lt;li&gt;Configuration type &lt;code&gt;mysqld&lt;/code&gt; changed to &lt;code&gt;mysql&lt;/code&gt; and now also usable for &lt;code&gt;mariadb&lt;/code&gt; and &lt;code&gt;postgresql&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;New variant of version comment added for MySQL 8.0.&lt;/li&gt;
&lt;li&gt;Comment added to &lt;code&gt;my_exec()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="myenv-installer"&gt;MyEnv Installer&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;mysql/mariadb fork installation implemented and tested.&lt;/li&gt;
&lt;li&gt;Example in &lt;code&gt;installMyEnv&lt;/code&gt; corrected/improved.&lt;/li&gt;
&lt;li&gt;Made nasty warning during installation of new instance go away.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="myenv-utilities"&gt;MyEnv Utilities&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;New script added.&lt;/li&gt;
&lt;li&gt;SSL added to monitor.&lt;/li&gt;
&lt;li&gt;Slave monitor made MySQL 8+ ready.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;checksum_table&lt;/code&gt; works now also with tables consisting of protected keywords.&lt;/li&gt;
&lt;li&gt;More debugging info added.&lt;/li&gt;
&lt;li&gt;All scripts checked by &lt;code&gt;shellcheck&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Missing runtime directory is caught and fixed now.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;shellcheck&lt;/code&gt; suggestions applied.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;checksum_table.sh&lt;/code&gt; added.&lt;/li&gt;
&lt;li&gt;Utility scripts brought to new state.&lt;/li&gt;
&lt;li&gt;Build slave script added.&lt;/li&gt;
&lt;li&gt;table diff refactored.&lt;/li&gt;
&lt;li&gt;Chunking added.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;table_diff&lt;/code&gt; is now ready for chunking.&lt;/li&gt;
&lt;li&gt;Faster checksum implemented and output shortened.&lt;/li&gt;
&lt;li&gt;Row by row crc32 checksum.&lt;/li&gt;
&lt;li&gt;Moved the checksum table in its own function.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;table_diff.php&lt;/code&gt; added.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="postgresql"&gt;PostgreSQL&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;show_create_table.sh&lt;/code&gt; for PostgreSQL added.&lt;/li&gt;
&lt;li&gt;PostgreSQL files added here until we have a better location.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="general"&gt;General&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Code clean-up and configuration check added.&lt;/li&gt;
&lt;li&gt;Recursive directory removal improved.&lt;/li&gt;
&lt;li&gt;rc made unique.&lt;/li&gt;
&lt;li&gt;Minor typos fixed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;my.cnf.template&lt;/code&gt; cleaned-up and synced with website.&lt;/li&gt;
&lt;li&gt;2 bugs with PHP 8.5 fixed.&lt;/li&gt;
&lt;li&gt;Libraries updated.&lt;/li&gt;
&lt;li&gt;Some return codes can be ignored because Redhat tools return error codes &amp;gt; 100 as OK.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="documentation"&gt;Documentation&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Documentation added and ready to start.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="packaging"&gt;Packaging&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Distro versions centralized in one place.&lt;/li&gt;
&lt;li&gt;Zabbix repo added for Ubuntu 24.04.&lt;/li&gt;
&lt;li&gt;Rocky 10 and Debian 11 added.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lxc&lt;/code&gt; replaced by &lt;code&gt;incus&lt;/code&gt;, distros cleaned-up.&lt;/li&gt;
&lt;li&gt;Ubuntu 24.04 and MariaDB 10.11 and 11.4 enabled.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brman&lt;/code&gt; as build project added.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;glb&lt;/code&gt; included in build scripts.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;restartContainer&lt;/code&gt; implemented.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gid&lt;/code&gt; and &lt;code&gt;uid&lt;/code&gt; added to &lt;code&gt;pushFileToContainer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Build cleaned-up.&lt;/li&gt;
&lt;li&gt;Build scrips improved.&lt;/li&gt;
&lt;li&gt;Container file push and pull added.&lt;/li&gt;
&lt;li&gt;Build infrastructure reorganized.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stopContainer&lt;/code&gt; and &lt;code&gt;startContainer&lt;/code&gt; added.&lt;/li&gt;
&lt;li&gt;Container library started.&lt;/li&gt;
&lt;li&gt;Debian 10 removed.&lt;/li&gt;
&lt;li&gt;Update container script is waiting to avoid infrastructure build failure.&lt;/li&gt;
&lt;li&gt;Old package for RPM changed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;install_base&lt;/code&gt; separted from &lt;code&gt;mysql_home&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Installation moved from &lt;code&gt;/home/mysql&lt;/code&gt; to &lt;code&gt;/opt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Fix DEB package.&lt;/li&gt;
&lt;li&gt;Ubuntu 22.04 added for package build.&lt;/li&gt;
&lt;li&gt;Bug in Debian build script fixed.&lt;/li&gt;
&lt;li&gt;Ubuntu 24.04 added to build infrastructure.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;recreate_build_infrastructure.sh&lt;/code&gt; rewritten in PHP.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;update_container_templates.sh&lt;/code&gt; rewritten in PHP.&lt;/li&gt;
&lt;li&gt;Made package build infrastructure more generic.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For subscriptions of commercial use of MyEnv please &lt;a href="mailto:contact@fromdual.com?Subject=Commercial use of MyEnv"&gt;get in contact&lt;/a&gt; with us.&lt;/p&gt;</description></item><item><title>Attribute promotion and demotion in the MariaDB Galera Cluster</title><link>https://www.fromdual.com/blog/attribute-promotion-and-demotion-in-the-mariadb-galera-cluster/</link><pubDate>Fri, 28 Nov 2025 16:26:48 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/attribute-promotion-and-demotion-in-the-mariadb-galera-cluster/</guid><description>&lt;p&gt;In MariaDB master/slave replication there is a feature called &lt;a href="https://mariadb.com/docs/server/ha-and-performance/standard-replication/replication-when-the-primary-and-replica-have-different-table-definitions" target="_blank"&gt;attribute promotion/demotion&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Simply put, it is about how the slave behaves or should behave if the master and slave have different column definitions or even a different number of columns or a different sequence of columns.&lt;/p&gt;
&lt;h2 id="use-case-of-the-customer"&gt;Use case of the customer&lt;/h2&gt;
&lt;p&gt;This week we discussed with a customer the case of how he could perform a rolling schema upgrade (RSU) in a Galera cluster.&lt;/p&gt;
&lt;p&gt;With previous schema changes he has always had problems, which has led to a total failure of the cluster for several hours.&lt;/p&gt;
&lt;p&gt;The customer says that columns are never deleted and new columns are only ever added at the end of a table.&lt;/p&gt;
&lt;p&gt;And that it is NOT possible to ensure that there are no more write connections during the rolling schema upgrade.&lt;/p&gt;
&lt;p&gt;The PHP ORM framework &lt;a href="https://www.doctrine-project.org/" target="_blank"&gt;Doctrine&lt;/a&gt; is used.&lt;/p&gt;
&lt;h2 id="what-does-the-mariadb-documentation-say-about-this"&gt;What does the MariaDB documentation say about this?&lt;/h2&gt;
&lt;p&gt;The study of the MariaDB documentation did not lead to a conclusive result whether a rolling schema upgrade in the running Galera Cluster operation WITH changes (DML statements) on the schema to be changed (AND the tables to be changed) is supported or not and thus should work or not.&lt;/p&gt;
&lt;p&gt;Source: &lt;a href="https://mariadb.com/docs/galera-cluster/galera-management/general-operations/performing-schema-upgrades-in-galera-cluster#rolling-schema-upgrade-rsu" target="_blank"&gt;Rolling Schema Upgrade (RSU)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When replicating with different table structures, there is only general information on replication but nothing specific to Galera (whether it works or not):&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;ldquo;Tables on the replica and the primary do not need to have the same definition in order for replication to take place. There can be differing numbers of columns, or differing data definitions and, in certain cases, replication can still proceed.&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Source: &lt;a href="https://mariadb.com/docs/server/ha-and-performance/standard-replication/replication-when-the-primary-and-replica-have-different-table-definitions" target="_blank"&gt;Replication When the Primary and Replica Have Different Table Definitions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For the attribute promotion/demotion feature there is a special MariaDB Server configuration parameter that controls the behaviour: &lt;code&gt;slave_type_conversions&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you read between the lines here, this could also work for Galera Cluster:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;ldquo;Determines the type conversion mode on the replica when using row-based replication, including replications in MariaDB Galera cluster.&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Source: &lt;a href="https://mariadb.com/docs/server/ha-and-performance/standard-replication/replication-and-binary-log-system-variables#slave_type_conversions" target="_blank"&gt;&lt;code&gt;slave_type_conversions&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="test-planning"&gt;Test planning&lt;/h2&gt;
&lt;p&gt;I always make a rough risk assessment for such questions: Frequently used and widely deployed features: Risk of problems is rather low. Rarely used or new features: risk of problems is high! Unfortunately, this assessment is based less on tangible figures and more on experience&amp;hellip;&lt;/p&gt;
&lt;p&gt;I am not aware of a single MariaDB user who performs rolling schema upgrades during operation. Let alone having a write load on the current schema and the current tables (promotion/demotion attributes).
So: Use of rolling schema upgrade x frequency of use of attribute promotion/demotion is very rare and therefore the risk is very high!&lt;/p&gt;
&lt;p&gt;As the situation is not clear and the documentation does not provide any clear information, testing was carried out.&lt;/p&gt;
&lt;p&gt;To avoid possible already fixed MariaDB bugs the latest MariaDB 11.8.5 LTS version was used.&lt;/p&gt;
&lt;p&gt;Special database configuration parameters were used:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;slave_type_conversions = 'ALL_NON_LOSSY,ALL_LOSSY'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our test table looks as usual as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE `test` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `data` varchar(128) DEFAULT NULL,
 `ts` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
 PRIMARY KEY (`id`)
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And test data was generated as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;INSERT INTO test VALUES (NULL, 'Some data to fill table up', NOW());
... -- 9 x
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Commands for monitoring the tests:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SHOW GLOBAL VARIABLES LIKE 'slave_type_conversions';
SQL&amp;gt; SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment';
SQL&amp;gt; SHOW CREATE TABLE test&amp;lt;br&amp;gt;G
SQL&amp;gt; CHECKSUM TABLE test;
SQL&amp;gt; SELECT * FROM test;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="testing"&gt;Testing&lt;/h2&gt;
&lt;h3 id="test-1-attribute-promotion-with-dml-remote-on-node-c"&gt;Test 1: Attribute promotion with DML remote (on Node C)&lt;/h3&gt;
&lt;p&gt;This is the simplest case: A column is added and a default value is set. Changes to the table are made on another node:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nodeA&amp;gt; SET SESSION wsrep_OSU_method = 'RSU';
nodeA&amp;gt; ALTER TABLE test ADD COLUMN c1 VARCHAR(64) NOT NULL DEFAULT 'foo';
nodeA&amp;gt; SET SESSION wsrep_OSU_method = 'TOI';
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MariaDB error log file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2025-11-28 9:39:11 0 [Note] WSREP: Member 0.0 (Node A) desyncs itself from group
2025-11-28 9:39:11 0 [Note] WSREP: Shifting SYNCED→DONOR/DESYNCED (TO: 36)
2025-11-28 9:39:11 13 [Note] WSREP: pause
2025-11-28 9:39:11 13 [Note] WSREP: Provider paused at 22db9ea1-cb7b-11f0-b26e-6fbce72757f9:36 (43)
2025-11-28 9:39:11 13 [Note] WSREP: Provider paused at: 36
2025-11-28 9:39:11 13 [Note] WSREP: resume
2025-11-28 9:39:11 13 [Note] WSREP: resuming provider at 43
2025-11-28 9:39:11 13 [Note] WSREP: Provider resumed.
2025-11-28 9:39:11 0 [Note] WSREP: Member 0.0 (Node A) resyncs itself to group.
2025-11-28 9:39:11 0 [Note] WSREP: Shifting DONOR/DESYNCED→JOINED (TO: 36)
2025-11-28 9:39:11 0 [Note] WSREP: Processing event queue:... -nan% (0/0 events) complete.
2025-11-28 9:39:11 0 [Note] WSREP: Member 0.0 (Node A) synced with group.
2025-11-28 9:39:11 0 [Note] WSREP: Processing event queue:... 100.0% (1/1 events) complete.
2025-11-28 9:39:11 0 [Note] WSREP: Shifting JOINED→SYNCED (TO: 36)
2025-11-28 9:39:11 7 [Note] WSREP: Server Node A synced with group
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then the other commands:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nodeC&amp;gt; INSERT INTO test VALUES (NULL, 'Some data to fill table up', NOW());
nodeC&amp;gt; UPDATE test SET data = 'Some data changed' WHERE id = 10;
nodeC&amp;gt; DELETE FROM test WHERE id = 19;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;ALTER TABLE&lt;/code&gt; command was then executed on nodes 2 and 3.&lt;/p&gt;
&lt;p&gt;All 3 operations worked perfectly. The cluster is still fully functional. Subsequently:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; ALTER TABLE test DROP COLUMN c1;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to return the system to its initial state for further tests.&lt;/p&gt;
&lt;h3 id="test-2-attribute-promotion-with-dml-remote-on-node-b"&gt;Test 2: Attribute promotion with DML remote (on node B)&lt;/h3&gt;
&lt;p&gt;If you do the same experiment on node B, the cluster will blow up in your face!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nodeB&amp;gt; INSERT INTO test VALUES (NULL, 'Some data to fill table up', NOW());

nodeC&amp;gt; SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment';
+---------------------------+--------------+
| Variable_name | Value |
+---------------------------+--------------+
| wsrep_local_state_comment | Inconsistent |
+---------------------------+--------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MariaDB error log file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Note] WSREP: Member 1(Node A) initiates vote on 22db9ea1-cb7b-11f0-b26e-6fbce72757f9:45,dbc9a6ea898b6a29: Got error 171 &amp;quot;The event was corrupt, leading to illegal data being read&amp;quot; from storage engine InnoDB, Error_code: 1030;
[Note] WSREP: Votes over 22db9ea1-cb7b-11f0-b26e-6fbce72757f9:45:
 dbc9a6ea898b6a29: 1/3
Waiting for more votes.
[Note] WSREP: Member 2(Node C) initiates vote on 22db9ea1-cb7b-11f0-b26e-6fbce72757f9:45,dbc9a6ea898b6a29: Got error 171 &amp;quot;The event was corrupt, leading to illegal data being read&amp;quot; from storage engine InnoDB, Error_code: 1030;
[Note] WSREP: Votes over 22db9ea1-cb7b-11f0-b26e-6fbce72757f9:45:
 dbc9a6ea898b6a29: 2/3
Winner: dbc9a6ea898b6a29
[Note] WSREP: Got vote request for seqno 22db9ea1-cb7b-11f0-b26e-6fbce72757f9:45
[Note] WSREP: Recovering vote result from history: 22db9ea1-cb7b-11f0-b26e-6fbce72757f9:45,dbc9a6ea898b6a29
[ERROR] WSREP: Vote 0 (success) on 22db9ea1-cb7b-11f0-b26e-6fbce72757f9:45 is inconsistent with group. Leaving cluster.
[Note] WSREP: Closing send monitor...
[Note] WSREP: Closed send monitor.
[Note] WSREP: gcomm: terminating thread
[Note] WSREP: gcomm: joining thread
[Note] WSREP: gcomm: closing backend
[Note] WSREP: view(view_id(NON_PRIM,1456a640-aca0,15) memb {
 1456a640-aca0,0
} joined {
} left {
} partitioned {
 97230fdb-b973,0
 a2e10f2c-8929,0
})
[Note] WSREP: PC protocol downgrade 1→0
[Note] WSREP: view((empty))
[Note] WSREP: gcomm: closed
[Note] WSREP: New COMPONENT: primary = no, bootstrap = no, my_idx = 0, memb_num = 1
[Note] WSREP: Flow-control interval: [16, 16]
[Note] WSREP: Received NON-PRIMARY.
[Note] WSREP: Shifting SYNCED→OPEN (TO: 45)
[Note] WSREP: New SELF-LEAVE.
[Note] WSREP: Flow-control interval: [0, 0]
[Note] WSREP: Received SELF-LEAVE. Closing connection.
[Note] WSREP: Shifting OPEN→CLOSED (TO: 45)
[Note] WSREP: RECV thread exiting 0: Success
[Note] WSREP: recv_thread() joined.
[Note] WSREP: Closing send queue.
[Note] WSREP: Closing receive queue.
[Note] WSREP: ================================================
View:
 id: 22db9ea1-cb7b-11f0-b26e-6fbce72757f9:45
 status: non-primary
 protocol_version: 4
 capabilities: MULTI-MASTER, CERTIFICATION, PARALLEL_APPLYING, REPLAY, ISOLATION, PAUSE, CAUSAL_READ, INCREMENTAL_WS, UNORDERED, PREORDERED, STREAMING, NBO
 final: no
 own_index: 0
 members(1):
 0: 1456a640-cc36-11f0-aca0-e388a5f80ba9, Node B
=================================================
[Note] WSREP: Non-primary view
[Note] WSREP: Server status change synced→connected
[Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.
[Note] WSREP: ================================================
View:
 id: 22db9ea1-cb7b-11f0-b26e-6fbce72757f9:45
 status: non-primary
 protocol_version: 4
 capabilities: MULTI-MASTER, CERTIFICATION, PARALLEL_APPLYING, REPLAY, ISOLATION, PAUSE, CAUSAL_READ, INCREMENTAL_WS, UNORDERED, PREORDERED, STREAMING, NBO
 final: yes
 own_index: -1
 members(0):
=================================================
[Note] WSREP: Non-primary view
[Note] WSREP: Server status change connected→disconnected
[Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.
[Note] WSREP: Applier thread exiting ret: 6 thd: 2
[Note] WSREP: Applier thread exiting ret: 6 thd: 9
[Warning] Aborted connection 2 to db: 'unconnected' user: 'unauthenticated' host: '' (This connection closed normally without authentication)
[Note] WSREP: Applier thread exiting ret: 6 thd: 5
[Warning] Aborted connection 5 to db: 'unconnected' user: 'unauthenticated' host: '' (This connection closed normally without authentication)
[Warning] Aborted connection 9 to db: 'unconnected' user: 'unauthenticated' host: '' (This connection closed normally without authentication)
[Note] WSREP: Service thread queue flushed.
[Note] WSREP: ####### Assign initial position for certification: 00000000-0000-0000-0000-000000000000:-1, protocol version: 6
[Note] WSREP: Applier thread exiting ret: 0 thd: 6
[Warning] Aborted connection 6 to db: 'unconnected' user: 'unauthenticated' host: '' (This connection closed normally without authentication)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No idea why node B and C behave differently. But this makes the whole rolling schema upgrade (RSU) process completely arbitrary and unplannable.&lt;/p&gt;
&lt;p&gt;The whole thing was tested in different variants and the node sometimes becomes inconsistent and sometimes not.&lt;/p&gt;
&lt;p&gt;The inconsistent node B is synchronised back into the cluster via a forced SST.&lt;/p&gt;
&lt;h3 id="test-3-attribute-promotion-with-dml-remote-on-node-c"&gt;Test 3: Attribute promotion with DML remote (on node C)&lt;/h3&gt;
&lt;p&gt;This case is somewhat trickier, as no default value is specified.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nodeA&amp;gt; SET SESSION wsrep_OSU_method = 'RSU';
nodeA&amp;gt; ALTER TABLE test ADD COLUMN c1 VARCHAR(64) NOT NULL; -- DEFAULT ''
nodeA&amp;gt; SET SESSION wsrep_OSU_method = 'TOI';

nodeC&amp;gt; INSERT INTO test VALUES (NULL, 'Some data to fill table up', NOW());
nodeC&amp;gt; UPDATE test SET data = 'Some data changed' WHERE id = 13;
nodeC&amp;gt; DELETE FROM test WHERE id = 22;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;ALTER TABLE&lt;/code&gt; command was then executed on nodes 2 and 3.&lt;/p&gt;
&lt;p&gt;All 3 operations worked perfectly. The cluster is still fully functional.&lt;/p&gt;
&lt;h3 id="test-4-attribute-promotion-with-dml-remote-on-node-b"&gt;Test 4: Attribute promotion with DML remote (on node B)&lt;/h3&gt;
&lt;p&gt;Same test but the &lt;code&gt;ALTER TABLE ADD COLUMN&lt;/code&gt; command is executed on node A and the DML command on node B.&lt;/p&gt;
&lt;p&gt;Nodes A and C become &amp;ldquo;Inconsistent&amp;rdquo; and node B is still &amp;ldquo;Synced&amp;rdquo;.&lt;/p&gt;
&lt;h3 id="test-5-attribute-promotion-with-dml-locally-on-node-a"&gt;Test 5: Attribute promotion with DML locally (on node A)&lt;/h3&gt;
&lt;p&gt;Analogue test but the DML command is executed locally on the same node as the DDL command.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nodeA&amp;gt; SET SESSION wsrep_OSU_method = 'RSU';
nodeA&amp;gt; ALTER TABLE test ADD COLUMN c1 VARCHAR(64) NOT NULL; -- DEFAULT ''
nodeA&amp;gt; SET SESSION wsrep_OSU_method = 'TOI';

nodeA&amp;gt; INSERT INTO test VALUES (NULL, 'Some data to fill table up', NOW());
ERROR 1136 (21S01): Column count doesn't match value count at row 1

nodeA&amp;gt; INSERT INTO test (id, data, ts) VALUES (NULL, 'Some data to fill table up', NOW());
ERROR 1364 (HY000): Field 'c1' doesn't have a default value

nodeA&amp;gt; INSERT INTO test (id, data, ts, c1) VALUES (NULL, 'Some data to fill table up', NOW(), '');

nodeA&amp;gt; SELECT * FROM test;
ERROR 1047 (08S01): WSREP has not yet prepared node for application use

nodeA&amp;gt; SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment';
+---------------------------+--------------+
| Variable_name | Value |
+---------------------------+--------------+
| wsrep_local_state_comment | Inconsistent |
+---------------------------+--------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cluster node became inconsistent. Interestingly enough, the whole thing suddenly worked during further testing! So completely unpredictable&amp;hellip;&lt;/p&gt;
&lt;h3 id="test-6-ddl-on-2-nodes"&gt;Test 6: DDL on 2 nodes&lt;/h3&gt;
&lt;p&gt;New question: What happens after the DDL command has been executed on 2 nodes and then DML commands occur?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nodeA&amp;gt; SET SESSION wsrep_OSU_method = 'RSU';
nodeA&amp;gt; ALTER TABLE test ADD COLUMN c1 VARCHAR(64) NOT NULL DEFAULT 'foo';
nodeA&amp;gt; SET SESSION wsrep_OSU_method = 'TOI';

nodeB&amp;gt; SET SESSION wsrep_OSU_method = 'RSU';
nodeB&amp;gt; ALTER TABLE test ADD COLUMN c1 VARCHAR(64) NOT NULL DEFAULT 'foo';
nodeB&amp;gt; SET SESSION wsrep_OSU_method = 'TOI';

nodeC&amp;gt; INSERT INTO test (id, data, ts) VALUES (NULL, 'Some data to fill table up', NOW());
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;works, but:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nodeB&amp;gt; INSERT INTO test (id, data, ts) VALUES (NULL, 'Some data to fill table up', NOW());

root@localhost [test]&amp;gt; SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment';
+---------------------------+--------------+
| Variable_name | Value |
+---------------------------+--------------+
| wsrep_local_state_comment | Inconsistent |
+---------------------------+--------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="test-7-update-and-delete-commands-from-the-same-node"&gt;Test 7: UPDATE and DELETE commands from the same node&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;nodeA&amp;gt; SET SESSION wsrep_OSU_method = 'RSU';
nodeA&amp;gt; ALTER TABLE test ADD COLUMN c1 VARCHAR(64) NOT NULL DEFAULT 'foo';
nodeA&amp;gt; SET SESSION wsrep_OSU_method = 'TOI';

nodeA&amp;gt; UPDATE test SET data = 'Some data changed' WHERE id = 16;

nodeA&amp;gt; SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment';
+---------------------------+--------------+
| Variable_name | Value |
+---------------------------+--------------+
| wsrep_local_state_comment | Inconsistent |
+---------------------------+--------------+

nodeA&amp;gt; DELETE FROM test WHERE id = 25;
nodeA&amp;gt; SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment';
+---------------------------+--------+
| Variable_name | Value |
+---------------------------+--------+
| wsrep_local_state_comment | Synced |
+---------------------------+--------+

...
[Warning] WSREP: Ignoring error 'Can't find record in 'test'' on Delete_rows_v1 event. Error_code: 1032
[Warning] Slave SQL: Could not execute Delete_rows_v1 event on table test.test; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find record in 'test', Error_code: 1032; Can't find re
[ERROR] Slave SQL: Could not read field 'id' of table 'test.test', Internal MariaDB error code: 1610
[ERROR] mariadbd: Can't find record in 'test'
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Process list from node C:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nodeC&amp;gt; SHOW PROCESSLIST;
+----+-------------+-----------+------+---------+------+-------------------------+----------------------------------------------------------------------------------------+----------+
| Id | User | Host | db | Command | Time | State | Info | Progress |
+----+-------------+-----------+------+---------+------+-------------------------+----------------------------------------------------------------------------------------+----------+
| 2 | system user | | NULL | Sleep | 1670 | After apply log event | NULL | 0.000 |
| 1 | system user | | NULL | Sleep | 4609 | wsrep aborter idle | NULL | 0.000 |
| 7 | system user | | NULL | Sleep | 4608 | | NULL | 0.000 |
| 8 | system user | | test | Sleep | 1441 | Executing | DELETE FROM test WHERE id = 25?5jR | 0.000 |
| 10 | system user | | NULL | Sleep | 2002 | wsrep applied write set | INSERT INTO test (id, data, ts) VALUES (NULL, 'Some data to fill table up', NOW()) 9O? | 0.000 |
| 28 | root | localhost | NULL | Query | 0 | starting | show processlist | 0.000 |
+----+-------------+-----------+------+---------+------+-------------------------+----------------------------------------------------------------------------------------+----------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Node C is still synchronised:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nodeC&amp;gt; SHOW GLOBAL STATUS LIKE 'wsrep_local_state_comment';
+---------------------------+--------+
| Variable_name | Value |
+---------------------------+--------+
| wsrep_local_state_comment | Synced |
+---------------------------+--------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Shutdown of the node for the following error message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nodeC&amp;gt; SQL&amp;gt; shutdown;
ERROR 1047 (08S01): WSREP has not yet prepared node for application use
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The entire cluster was then no longer usable. And had to be restarted (bootstrap).&lt;/p&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;We have opened a bug at MariaDB on this topic: &lt;a href="https://jira.mariadb.org/browse/MDEV-38215" target="_blank"&gt;Attribute Promotion/Demotion in Galera Cluster&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Further tests were not carried out for the time being, as this feature is too unstable in the tested version and &lt;code&gt;DROP COLUMN&lt;/code&gt; is not a use case of our customer.&lt;/p&gt;
&lt;p&gt;Conclusion: MariaDB Galera Cluster does not properly handle this situation in the version tested, nor does the cluster prevent this case. Cluster nodes are marked as inconsistent. Our current recommendation: Do NOT do a rolling schema upgrade (RSU) with concurrent DML commands (&lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;) on the tables to be changed with the analysed version!&lt;/p&gt;
&lt;p&gt;Further sources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://galeracluster.com/documentation/html_docs_2023/_sources/documentation/inconsistency-voting.rst.txt" target="_blank"&gt;Galera Cluster Inconsistency Voting protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.percona.com/blog/inconsistent-voting-in-percona-xtradb-cluster/" target="_blank"&gt;Inconsistent Voting in Percona XtraDB Cluster&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>FromDual Backup and Recovery Manager for MariaDB and MySQL 2.3.2 has been released</title><link>https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.3.2-has-been-released/</link><pubDate>Wed, 22 Oct 2025 20:41:15 +0200</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.3.2-has-been-released/</guid><description>&lt;p&gt;FromDual has the pleasure to announce the release of the new version 2.3.2 of its popular &lt;a href="https://www.fromdual.com/backup-and-recovery-manager-user-guide" title="FromDual Backup and Recovery Manager for MariaDB and MySQL"&gt;Backup and Recovery Manager for MariaDB and MySQL&lt;/a&gt; (&lt;code&gt;brman&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The new FromDual Backup and Recovery Manager can be downloaded from &lt;a href="https://support.fromdual.com/admin/public/download.php?operation=select&amp;amp;product_id=12&amp;amp;release_series_id=28&amp;amp;product_version_id=154" title="Download FromDual Backup and Recovery Manager for MariaDB and MySQL"&gt;here&lt;/a&gt;. The FromDual Repositories were updated. How to install and use the Backup and Recovery Manager is described in &lt;a href="https://www.fromdual.com/fromdual-backup-and-recovery-manager-installation-guide" title="FromDual Backup and Recovery Manager (brman) installation guide"&gt;FromDual Backup and Recovery Manager (&lt;code&gt;brman&lt;/code&gt;) installation guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the inconceivable case that you find a bug in the FromDual Backup and Recovery Manager please send us an [email](mailto:contact@fromdual.com?Subject=Bug report for brman).&lt;/p&gt;
&lt;p&gt;Any feedback, statements and testimonials are welcome as well! Please send them to &lt;a href="mailto:feedback@fromdual.com?Subject=Feedback"&gt;feedback@fromdual.com&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="upgrade-from-2x-to-232"&gt;Upgrade from 2.x to 2.3.2&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ cd /opt
$ tar xf /download/brman-2.3.2.tar.gz
$ rm -f brman
$ ln -s brman-2.3.2 brman
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="changes-in-fromdual-backup-and-recovery-manager-232"&gt;Changes in FromDual Backup and Recovery Manager 2.3.2&lt;/h2&gt;
&lt;p&gt;This release is a new minor release. It contains mainly bug fixes. We have tried to maintain backward-compatibility with the 1.2, 2.0, 2.1, 2.2 and 2.3 release series. But you should test the new release seriously!&lt;/p&gt;
&lt;p&gt;You can verify your current FromDual Backup Manager version with the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ bman --version
$ rman --version
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="general"&gt;General&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Tests improved.&lt;/li&gt;
&lt;li&gt;New features documented and documentation updated.&lt;/li&gt;
&lt;li&gt;Libraries from MyEnv project updated.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="fromdual-backup-manager-bman"&gt;FromDual Backup Manager (bman)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;SSL/TLS implemented for &lt;code&gt;bman&lt;/code&gt; only.&lt;/li&gt;
&lt;li&gt;Binary log position should be gathered correctly now also with MySQL 8.4.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="fromdual-recovery-manager-rman"&gt;FromDual Recovery Manager (rman)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;No changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Subscriptions for commercial use of FromDual Backup and Recovery Manager you can get from [from us](mailto:contact@fromdual.com?Subject=Commercial use of FromDual brman).&lt;/p&gt;</description></item><item><title>MariaDB Honeypot</title><link>https://www.fromdual.com/blog/mariadb-honeypot/</link><pubDate>Thu, 06 Mar 2025 09:50:18 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/mariadb-honeypot/</guid><description>&lt;p&gt;In our &lt;a href="https://www.fromdual.com/advanced-mysql-mariadb-training"&gt;MariaDB advanced training courses&lt;/a&gt;, which we hold approximately every two months, we use machines that are directly exposed to the Internet with a public IP address.
&lt;strong&gt;Warning&lt;/strong&gt;: You should NEVER expose a database directly to the Internet without protection!
Typically, it takes less than 72 hours (3 days) before we are exposed to the first external access attempts.&lt;/p&gt;
&lt;p&gt;This looks something like this in the MariaDB error log:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] Aborted connection 22939 to db: 'unconnected' user: 'unauthenticated' host: '118.193.58.125' (This connection closed normally without authentication)
[Warning] Aborted connection 22940 to db: 'unconnected' user: 'unauthenticated' host: '118.193.58.125' (This connection closed normally without authentication)
[Warning] Access denied for user ''@'118.193.58.125' (using password: NO)
[Warning] Access denied for user 'root'@'118.193.58.125' (using password: YES)
[Warning] Access denied for user 'root'@'118.193.58.125' (using password: YES)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First of all, it was checked whether a database is listening and how it responds. Then various attempts are made to penetrate the database. It looks like there are various sampling and attack patterns. The anonymous user (&lt;code&gt;''@'%'&lt;/code&gt;) and &lt;code&gt;'root'@'%'&lt;/code&gt; are checked with and without a password.
Whether other users will be tested remains to be seen over a longer observation period.&lt;/p&gt;
&lt;p&gt;And this is what it looks like from the MariaDB General Query Log:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;287793 Connect root@196.251.91.77 on using TCP/IP
287793 Connect Access denied for user 'root'@'196.251.91.77' (using password: NO)
287794 Connect root@196.251.91.77 on using TCP/IP
287794 Connect Access denied for user 'root'@'196.251.91.77' (using password: YES)
287796 Connect root@196.251.91.77 on using TCP/IP
287796 Connect Access denied for user 'root'@'196.251.91.77' (using password: YES)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="preparing-the-honeypot"&gt;Preparing the honeypot&lt;/h2&gt;
&lt;p&gt;At the end of the training, we no longer need the machines, they will be removed. That&amp;rsquo;s why I was tempted to try out what happens when an access attempt is successful. To test this, the user &lt;code&gt;'root'@'%'&lt;/code&gt; was created without a password as follows and given all rights to the &lt;code&gt;test&lt;/code&gt; schema:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; CREATE USER 'root'@'%';
SQL&amp;gt; GRANT ALL ON test.* TO 'root'@'%';
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and both the MariaDB General Log was switched on and the MariaDB Error Log was made more talkative:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# my.cnf

[server]

general_log_file = /var/log/mysql/general.log
general_log = on
log_error = /var/log/mysql/error.log
log_warnings = 9 # too much!
bind_address = *
skip_name_resolve = on # How much info do we loose?
# skip_grant_tables
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that it was just a matter of lying in wait and seeing what happens&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TODO&lt;/strong&gt;: It would be interesting to see which passwords are used to access the database. Let&amp;rsquo;s see if we can find out without patching the MariaDB source code&amp;hellip;? Maybe one should also try using &lt;code&gt;wireshark&lt;/code&gt; or &lt;code&gt;tcpdump&lt;/code&gt; to make the passwords visible.&lt;/p&gt;
&lt;h2 id="the-first-fly-buzzes-in"&gt;The first fly buzzes in&lt;/h2&gt;
&lt;p&gt;Then the first fly (from Amsterdam, Netherlands) seems to arrive at the honeypot. First we have a warning that the reverse lookup of the IP address fails:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] Hostname 'no-reverse-dns-configured.com' does not resolve to '94.102.49.155'.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But then it goes in. But doesn&amp;rsquo;t do anything exciting:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;250228 16:06:32 1222 Connect root@94.102.49.155 on using TCP/IP
 1222 Query SHOW databases
 1222 Query SHOW tables IN information_schema
 1222 Query SHOW tables IN test
 1222 Query SHOW VARIABLES
250228 16:06:33 1222 Quit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What does the fly get to see:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SHOW databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| test |
+--------------------+

SQL&amp;gt; SHOW tables IN information_schema;
+-------------------------------+
| Tables_in_information_schema |
+-------------------------------+
| ALL_PLUGINS |
| APPLICABLE_ROLES |
| CHARACTER_SETS |
| ... |
| INNODB_TABLESPACES_ENCRYPTION |
| INNODB_LOCK_WAITS |
| THREAD_POOL_STATS |
+-------------------------------+
82 rows in set (0.000 sec)

SQL&amp;gt; SHOW tables IN test;
+----------------+
| Tables_in_test |
+----------------+
| test |
+----------------+

SQL&amp;gt; SHOW VARIABLES;
+----------------------------------------------------------+------------+
| Variable_name | Value |
+----------------------------------------------------------+------------+
| allow_suspicious_udfs | OFF |
| alter_algorithm | DEFAULT |
| analyze_sample_percentage | 100.000000 |
| ... | |
| wsrep_sync_wait | 0 |
| wsrep_trx_fragment_size | 0 |
| wsrep_trx_fragment_unit | bytes |
+----------------------------------------------------------+------------+
686 rows in set (0.003 sec)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Maybe the algorithm of the attack is smart enough here and realises that an attack is not worthwhile?&lt;/p&gt;
&lt;p&gt;Then we wait for the next fly&amp;hellip;&lt;/p&gt;
&lt;h2 id="the-next-fly-comes-flying"&gt;The next fly comes flying&lt;/h2&gt;
&lt;p&gt;And there it is (this time from the USA, Minneapolis) in the MariaDB error log:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] Hostname 'undefined.hostname.localhost' does not resolve to '196.251.83.136'.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now it will be interesting to see what exactly happens in the MariaDB General Query Log?&lt;/p&gt;
&lt;p&gt;First, a connection is established and kept open (keep your foot in the door?):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;250228 16:06:55 67 Connect root@196.251.83.136 on using TCP/IP
 67 Query SET AUTOCOMMIT=0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, 15 seconds later, a connection is opened and closed again (make sure you were really successful?):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;250228 16:07:10 68 Connect root@196.251.83.136 on using TCP/IP
 68 Query SET AUTOCOMMIT=0
 68 Quit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Immediately afterwards, all schemas are queried:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 69 Connect root@196.251.83.136 on using TCP/IP
 69 Query SET AUTOCOMMIT=0
 69 Query SHOW DATABASES
 69 Quit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then a connection is opened and closed again:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 70 Connect root@196.251.83.136 on using TCP/IP
 70 Query SET AUTOCOMMIT=0
 70 Quit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then a check is made to see how large the schema is. Probably to ensure that it is not too large? Then the tables are queried. The connection is kept open and work continues 2 seconds later.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 71 Connect root@196.251.83.136 on using TCP/IP
 71 Query SET AUTOCOMMIT=0
 71 Query SELECT SUM(data_length + index_length) FROM information_schema.tables WHERE table_schema = 'test'
 71 Query USE `test`
 71 Query SHOW tables
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then a &lt;code&gt;mariadb-dump&lt;/code&gt; imitation? with version ≥ 10.1 is started to read &lt;strong&gt;the first 10!!!! lines of the table&lt;/strong&gt; &lt;code&gt;aaa_payload&lt;/code&gt; in the schema &lt;code&gt;test&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;250228 16:07:11 72 Connect root@196.251.83.136 on using TCP/IP
 72 Query /*!40100 SET @@SQL_MODE='' */
 72 Query /*!100100 SET @@MAX_STATEMENT_TIME=0.000000 */
 72 Query /*!100100 SET WAIT_TIMEOUT=DEFAULT */
 72 Query set optimizer_switch='semijoin=off'
 72 Query SELECT LOGFILE_GROUP_NAME, FILE_NAME, TOTAL_EXTENTS, INITIAL_SIZE, ENGINE, EXTRA FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'UNDO LOG' AND FILE_NAME IS NOT NULL AND LOGFILE_GROUP_NAME IS NOT NULL AND LOGFILE_GROUP_NAME IN (SELECT DISTINCT LOGFILE_GROUP_NAME FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'DATAFILE' AND TABLESPACE_NAME IN (SELECT DISTINCT TABLESPACE_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA='test' AND TABLE_NAME IN ('aaa_payload'))) GROUP BY LOGFILE_GROUP_NAME, FILE_NAME, ENGINE, TOTAL_EXTENTS, INITIAL_SIZE ORDER BY LOGFILE_GROUP_NAME
 72 Query SELECT DISTINCT TABLESPACE_NAME, FILE_NAME, LOGFILE_GROUP_NAME, EXTENT_SIZE, INITIAL_SIZE, ENGINE FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'DATAFILE' AND TABLESPACE_NAME IN (SELECT DISTINCT TABLESPACE_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA='test' AND TABLE_NAME IN ('aaa_payload')) ORDER BY TABLESPACE_NAME, LOGFILE_GROUP_NAME
 72 Query set optimizer_switch=default
 72 Init DB test
 72 Query SHOW VARIABLES LIKE 'lower_case_table_names'
 72 Query SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'aaa_payload'
 72 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'aaa_payload'
 72 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'aaa_payload'
 72 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'aaa_payload'
 72 Query SET SQL_QUOTE_SHOW_CREATE=1
 72 Query show fields from `aaa_payload`
 72 Query SELECT /*!40001 SQL_NO_CACHE */ `id`, `name` FROM `aaa_payload` WHERE 1 LIMIT 10
 72 Quit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then the same again with a table called &lt;code&gt;bbb_payload&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 73 Connect root@196.251.83.136 on using TCP/IP
 73 Query /*!40100 SET @@SQL_MODE='' */
 73 Query /*!100100 SET @@MAX_STATEMENT_TIME=0.000000 */
 73 Query /*!100100 SET WAIT_TIMEOUT=DEFAULT */
 73 Query set optimizer_switch='semijoin=off'
 73 Query SELECT LOGFILE_GROUP_NAME, FILE_NAME, TOTAL_EXTENTS, INITIAL_SIZE, ENGINE, EXTRA FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'UNDO LOG' AND FILE_NAME IS NOT NULL AND LOGFILE_GROUP_NAME IS NOT NULL AND LOGFILE_GROUP_NAME IN (SELECT DISTINCT LOGFILE_GROUP_NAME FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'DATAFILE' AND TABLESPACE_NAME IN (SELECT DISTINCT TABLESPACE_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA='test' AND TABLE_NAME IN ('bbb_payload'))) GROUP BY LOGFILE_GROUP_NAME, FILE_NAME, ENGINE, TOTAL_EXTENTS, INITIAL_SIZE ORDER BY LOGFILE_GROUP_NAME
 73 Query SELECT DISTINCT TABLESPACE_NAME, FILE_NAME, LOGFILE_GROUP_NAME, EXTENT_SIZE, INITIAL_SIZE, ENGINE FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'DATAFILE' AND TABLESPACE_NAME IN (SELECT DISTINCT TABLESPACE_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA='test' AND TABLE_NAME IN ('bbb_payload')) ORDER BY TABLESPACE_NAME, LOGFILE_GROUP_NAME
 73 Query set optimizer_switch=default
 73 Init DB test
 73 Query SHOW VARIABLES LIKE 'lower_case_table_names'
250228 16:07:12 73 Query SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'bbb_payload'
 73 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'bbb_payload'
 73 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'bbb_payload'
 73 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'bbb_payload'
 73 Query SET SQL_QUOTE_SHOW_CREATE=1
 73 Query show fields from `bbb_payload`
 73 Query SELECT /*!40001 SQL_NO_CACHE */ `id`, `name` FROM `bbb_payload` WHERE 1 LIMIT 10
 73 Quit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally our main table &lt;code&gt;test&lt;/code&gt; but again &lt;strong&gt;only the first 10!!!! rows&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 74 Connect root@196.251.83.136 on using TCP/IP
 74 Query /*!40100 SET @@SQL_MODE='' */
 74 Query /*!100100 SET @@MAX_STATEMENT_TIME=0.000000 */
 74 Query /*!100100 SET WAIT_TIMEOUT=DEFAULT */
 74 Query set optimizer_switch='semijoin=off'
 74 Query SELECT LOGFILE_GROUP_NAME, FILE_NAME, TOTAL_EXTENTS, INITIAL_SIZE, ENGINE, EXTRA FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'UNDO LOG' AND FILE_NAME IS NOT NULL AND LOGFILE_GROUP_NAME IS NOT NULL AND LOGFILE_GROUP_NAME IN (SELECT DISTINCT LOGFILE_GROUP_NAME FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'DATAFILE' AND TABLESPACE_NAME IN (SELECT DISTINCT TABLESPACE_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA='test' AND TABLE_NAME IN ('test'))) GROUP BY LOGFILE_GROUP_NAME, FILE_NAME, ENGINE, TOTAL_EXTENTS, INITIAL_SIZE ORDER BY LOGFILE_GROUP_NAME
 74 Query SELECT DISTINCT TABLESPACE_NAME, FILE_NAME, LOGFILE_GROUP_NAME, EXTENT_SIZE, INITIAL_SIZE, ENGINE FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'DATAFILE' AND TABLESPACE_NAME IN (SELECT DISTINCT TABLESPACE_NAME FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_SCHEMA='test' AND TABLE_NAME IN ('test')) ORDER BY TABLESPACE_NAME, LOGFILE_GROUP_NAME
 74 Query set optimizer_switch=default
 74 Init DB test
 74 Query SHOW VARIABLES LIKE 'lower_case_table_names'
 74 Query SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'test'
 74 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'test'
 74 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'test'
 74 Query SELECT engine, table_type FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = 'test'
 74 Query SET SQL_QUOTE_SHOW_CREATE=1
 74 Query show fields from `test`
 74 Query SELECT /*!40001 SQL_NO_CACHE */ `id`, `data`, `ts` FROM `test` WHERE 1 LIMIT 10
 74 Quit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then it continues again with Connection 71: The 3 tables &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;bbb_payload&lt;/code&gt; and &lt;code&gt;aaa_payload&lt;/code&gt; are deleted:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 71 Query USE `test`
 71 Query SHOW TABLES
 71 Query SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = 'test' AND TABLE_NAME = 'test' AND REFERENCED_TABLE_NAME IS NOT NULL
 71 Query SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = 'test' AND TABLE_NAME = 'bbb_payload' AND REFERENCED_TABLE_NAME IS NOT NULL
250228 16:07:13 71 Query SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = 'test' AND TABLE_NAME = 'aaa_payload' AND REFERENCED_TABLE_NAME IS NOT NULL
 71 Query DROP TABLE `test`
 71 Query DROP TABLE `bbb_payload`
 71 Query DROP TABLE `aaa_payload`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then a table called &lt;code&gt;RECOVER_YOUR_DATA&lt;/code&gt; is created and provided with the text how to pay the ransom. The amount is 0.0101 Bitcoin, which currently corresponds to around EUR 863.40. Mind you, they only dumped the first 10 lines and then deleted them!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 71 Query CREATE TABLE IF NOT EXISTS RECOVER_YOUR_DATA (text VARCHAR(255))
 71 Query INSERT INTO RECOVER_YOUR_DATA (text) VALUES ('All your data is backed up. You must pay 0.0101 BTC to bc1qm0v2r0mmx3py3h7fzkerd9a6rzdrpw5afqacen In 48 hours, your data will be publicly disclosed and deleted. (more information: go to https://is.gd/yotuqu)')
 71 Query INSERT INTO RECOVER_YOUR_DATA (text) VALUES ('After payment send mail to us: rambler+2r8qm@onionmail.org and we will provide a link for you to download your data. Your DBCODE is: 2R8QM')
 71 Query COMMIT
 71 Quit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following text can be found behind the link:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Please take note of the following:

We are aware that you have accessed this guide.
This offer stands for 24hs

After 72 hours, we cannot guarantee that we will be able to send the data to you.
The only way to recover your data is by making the payment. We will not provide the data for free.

Data leakage is a serious legal violation. Rest assured, the incident will remain confidential, and your data is protected.

After your payment is completed, all data downloaded from you will be deleted from our servers, government agencies, competitors, contractors, and local media are currently unaware of the incident.

If you pay we guarantee that your data will not be sold on Darkweb resources and will not be used to attack your company, employees, or counterparties in the future and the full database dump will be sent to you.

If you have not contacted us within two days from the time of the incident, we will consider the transaction incomplete. Your data will then be sent to any interested parties. This is your responsibility.

If you are a system administrator or programmer and your boss is unaware of this incident, we will contact them after 48 hours.

If you are unable to contact us using the provided email, please visit https://getsession.org/ and download the Session Messenger. Add us using the following Session ID for a smoother conversation and better negotiation:
Session ID:
05a5ba6491a15908207cce6e257b3316cd11cb2575f75194d3c59c37de68eaf55a

After payment, please provide us with a screenshot or proof of payment.
Once the payment is confirmed, we will send you a download link for your data. We will also delete our copy of the data.

IMPORTANT!!
DO NOT FORGET TO INCLUDE YOUR DBCODE IN YOUR MAIL OR MESSAGE YOU SEND TO US

The only accepted payment method is Bitcoin.
Be advised: PayPal, WeTransfer, Alipay, credit cards, and other methods will not be accepted.
If you prefer to pay with another cryptocurrency, please contact us to make arrangements.

If you don't have Bitcoin, you can purchase it using a credit card from the following websites:

MoonPay: https://www.moonpay.com/buy
Paybis: https://paybis.com/
Changelly: https://changelly.com/buy

Alternatively, you can buy Bitcoin using other payment methods from the following platforms (some of them work in China):

Coinbase: https://www.coinbase.com/
Paxful: https://paxful.com/
Binance: https://www.binance.com/
Crypto.com: https://www.crypto.com/
Huobi: https://www.huobi.com/
OKCoin: https://www.okcoin.com/
BTCC: https://www.btcc.com/
Paybis: https://paybis.com/
Coinmama: https://coinmama.com/
Bitfinex: https://www.bitfinex.com/
For users in China, Bitcoin can be purchased with Alipay from:

CoinCola: https://www.coincola.com/?lang=zh-HK
BitValve: https://www.bitvalve.com/buy-bitcoin/alipay
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this text is written to the &lt;code&gt;RECOVER_YOUR_DATA&lt;/code&gt; table:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SELECT * FROM RECOVER_YOUR_DATA;
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| text |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| All your data is backed up. You must pay 0.0101 BTC to bc1qm0v2r0mmx3py3h7fzkerd9a6rzdrpw5afqacen In 48 hours, your data will be publicly disclosed and deleted. (more information: go to https://is.gd/yotuqu) |
| After payment send mail to us: rambler+2r8qm@onionmail.org and we will provide a link for you to download your data. Your DBCODE is: 2R8QM |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then the test schema (where the &lt;code&gt;RECOVER_YOUR_DATA&lt;/code&gt; table is contained?) is deleted.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 75 Connect root@196.251.83.136 on using TCP/IP
 75 Query SET AUTOCOMMIT=0
 75 Query DROP DATABASE `test`
 75 Query COMMIT
 75 Quit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And a new schema is created with the name &lt;code&gt;RECOVER_YOUR_DATA&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 76 Connect root@196.251.83.136 on using TCP/IP
 76 Query SET AUTOCOMMIT=0
 76 Query CREATE DATABASE IF NOT EXISTS RECOVER_YOUR_DATA
 76 Quit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Somehow the access doesn&amp;rsquo;t seem logical to me and still has potential. Since the &lt;code&gt;RECOVER_YOUR_DATA&lt;/code&gt; table is missing (deleted with schema &lt;code&gt;test&lt;/code&gt;), you can no longer pay if you wanted to&amp;hellip;&lt;/p&gt;
&lt;p&gt;Maybe the developer did not expect a limited &lt;code&gt;root&lt;/code&gt; account and therefore the tool behaves incorrectly? See also the three repetitions when dumping the tables.&lt;/p&gt;
&lt;h2 id="where-does-the-access-come-from"&gt;Where does the access come from?&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t know how well you can disguise where you are coming from and how good the geo-resolution of the IP addresses is, I don&amp;rsquo;t know enough about that. A search revealed that the &lt;a href="https://whatismyipaddress.com/ip/196.251.83.136" target="_blank"&gt;IP comes from Amsterdam (Netherlands)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After further research, it turned out that the IP belongs to an organisation called &lt;a href="https://myip.ms/view/ip_owners/1629066/Internet_Secuirty_Ekabi.html" target="_blank"&gt;Internet Secuirty Ekabi&lt;/a&gt; (note misspelling as in the original!) with an address in the USA and a &lt;a href="https://whois.ipip.net/AS401115" target="_blank"&gt;location in the Seychelles&lt;/a&gt;.
If anyone can give me any more tips on what I can find out, I would be very grateful!&lt;/p&gt;
&lt;h2 id="where-do-the-ip-addresses-come-from"&gt;Where do the IP addresses come from?&lt;/h2&gt;
&lt;p&gt;In the short period under observation, we observed access from the following regions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Alibaba Cloud, Singapore&lt;/li&gt;
&lt;li&gt;Google Belgium, Brussels&lt;/li&gt;
&lt;li&gt;Data-Center Imaqliq Ltd., Russia, St. Petersburg&lt;/li&gt;
&lt;li&gt;Alibaba Cloud, Japan, Tokyo&lt;/li&gt;
&lt;li&gt;FiberXpress BV, Netherlands, Amsterdam&lt;/li&gt;
&lt;li&gt;M247 Europe SRL, United Kingdom, Manchester&lt;/li&gt;
&lt;li&gt;Hetzner Online GmbH, Finland, Helsinki&lt;/li&gt;
&lt;li&gt;Internet Secuirty Ekabi, Netherlands, Amsterdam (2 x)&lt;/li&gt;
&lt;li&gt;Internet Security Cheapyhost, Netherlands, Amsterdam (9 x)&lt;/li&gt;
&lt;li&gt;Internet Security Nybula, Netherlands, Amsterdam (2 x)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="access-pattern"&gt;Access pattern&lt;/h2&gt;
&lt;p&gt;All access attempts are made WITHOUT SSL/TLS.&lt;/p&gt;
&lt;p&gt;Fingerprint from the perspective of the MariaDB General Query Log:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;9 x
Connect root@34.140.63.218 on using TCP/IP
Connect Access denied for user 'root'@'34.140.63.218' (using password: NO)

1 x
Connect root@45.135.95.25 on using TCP/IP
Connect Access denied for user 'root'@'45.135.95.25' (using password: NO)
Connect root@45.135.95.25 on using TCP/IP
Connect Access denied for user 'root'@'45.135.95.25' (using password: NO)

4 x
Connect root@196.251.118.8 on using TCP/IP
Connect Access denied for user 'root'@'196.251.118.8' (using password: NO)
Connect root@196.251.118.8 on using TCP/IP
Connect Access denied for user 'root'@'196.251.118.8' (using password: YES)
Connect root@196.251.118.8 on using TCP/IP
... mit 2 Wiederholungen

1 x
Connect root@94.102.49.155 on using TCP/IP
Connect Access denied for user 'root'@'94.102.49.155' (using password: NO)
Connect root@94.102.49.155 on using TCP/IP
Connect Access denied for user 'root'@'94.102.49.155' (using password: YES)
... mit 6 Wiederholungen

2 x
Connect root@196.251.91.19 on using TCP/IP
Connect Access denied for user 'root'@'196.251.91.19' (using password: NO)
Connect root@196.251.91.19 on using TCP/IP
Connect Access denied for user 'root'@'196.251.91.19' (using password: YES)
... mit 28 Wiederholungen

1 x
Connect root@157.180.29.231 on using TCP/IP
Connect Access denied for user 'root'@'157.180.29.231' (using password: NO)
Connect root@157.180.29.231 on using TCP/IP
Connect Access denied for user 'root'@'157.180.29.231' (using password: NO)
Connect root@157.180.29.231 on using TCP/IP
Connect Access denied for user 'root'@'157.180.29.231' (using password: YES)
Connect root@157.180.29.231 on using TCP/IP
Connect Access denied for user 'root'@'157.180.29.231' (using password: YES)
Mit jeweils zeitlichem Abstand

2 x
Connect root@196.251.86.26 on using TCP/IP
Connect Access denied for user 'root'@'196.251.86.26' (using password: NO)
Connect root@196.251.86.26 on using TCP/IP
Connect Access denied for user 'root'@'196.251.86.26' (using password: YES)
Connect root@196.251.86.26 on using TCP/IP
... mit 38 Wiederholungen
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is of course possible that some of these access attempts use the same tools and were simply cancelled after a different number of attempts and the tools thus generated a different pattern.&lt;/p&gt;
&lt;h2 id="access-pattern-from-the-perspective-of-the-mariadb-error-log"&gt;Access pattern from the perspective of the MariaDB error log&lt;/h2&gt;
&lt;h3 id="possible-accesses-to-the-galera-protocol"&gt;Possible accesses to the Galera Protocol&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;[Warning] WSREP: Failed to unserialize message. This may be a result of corrupt message, port scanner or another application connecting to group communication port.
[Warning] WSREP: Failed to unserialize message. This may be a result of corrupt message, port scanner or another application connecting to group communication port.
[Warning] WSREP: Unsupported/unrecognized gmcast protocol version: {
 at ./gcomm/src/gmcast_message.hpp:unserialize():331
 at ./gcomm/src/gmcast.cpp:handle_up():1494
[Warning] WSREP: Failed to unserialize message. This may be a result of corrupt message, port scanner or another application connecting to group communication port.
[Warning] WSREP: Failed to unserialize message. This may be a result of corrupt message, port scanner or another application connecting to group communication port.
[Warning] WSREP: Failed to unserialize message. This may be a result of corrupt message, port scanner or another application connecting to group communication port.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] WSREP: Failed to unserialize message. This may be a result of corrupt message, port scanner or another application connecting to group communication port.
[Warning] WSREP: Failed to unserialize message. This may be a result of corrupt message, port scanner or another application connecting to group communication port.
[Warning] WSREP: Failed to unserialize message. This may be a result of corrupt message, port scanner or another application connecting to group communication port.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Whether this was an access attempt or whether we only had a problem in our network or Galera cluster still needs to be verified.&lt;/p&gt;
&lt;h2 id="problems-with-the-name-resolution"&gt;Problems with the name resolution&lt;/h2&gt;
&lt;p&gt;To get more and additional information the database was run WITHOUT &lt;code&gt;skip_name_resolve&lt;/code&gt;. This leads to various warnings regarding name resolution (forwards and backwards).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] Hostname 'no-reverse-dns-configured.com' does not resolve to '94.102.49.155'.
[Warning] Host name 'scanner-28.ch1.censys-scanner.com' could not be resolved: Name or service not known
[Warning] IP address '34.140.170.97' has been resolved to the host name '97.170.140.34.bc.googleusercontent.com', which resembles IPv4-address itself.
[Warning] IP address '165.154.100.58' could not be resolved: Name or service not known
[Warning] IP address '104.193.135.104' could not be resolved: Temporary failure in name resolution
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In addition, various scanner systems were noticed, some of which resolved correctly: security.ipip.net coop.net {ch1|hk2}.censys-scanner.com&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;: &lt;code&gt;slog_warnings = 9&lt;/code&gt; is too high, activate &lt;code&gt;skip_name_resolve&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="port-probing"&gt;Port probing&lt;/h2&gt;
&lt;p&gt;Simple port probing (tapping the ports) can be done as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# netcat -z -n -v 10.116.63.139 3300-3310
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the MariaDB error log on the database page you will see the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] Could not read packet: fd: 56 state: 1 read_length: 4 errno: 110 vio_errno: 1159 length: 0
[Warning] Aborted connection 52 to db: 'unconnected' user: 'unauthenticated' host: '_gateway.incus' (This connection closed normally without authentication)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These port probes are not even displayed in the MariaDB general query log.&lt;/p&gt;
&lt;h2 id="different-variants-and-patterns-of-port-probing"&gt;Different variants and patterns of port probing&lt;/h2&gt;
&lt;p&gt;We have noticed the following 3 patterns of port probing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] Could not read packet: fd: 63 state: 1 read_length: 4 errno: 104 vio_errno: 1158 length: -1
[Warning] Aborted connection 76 to db: 'unconnected' user: 'unauthenticated' host: '45.142.193.153' (This connection closed normally without authentication)

198.235.24.140 115.231.78.10
[Warning] Could not read packet: fd: 63 state: 1 read_length: 4 errno: 11 vio_errno: 1158 length: 0
[Warning] Aborted connection 50 to db: 'unconnected' user: 'unauthenticated' host: '20.65.194.133' (This connection closed normally without authentication)

[Warning] Could not write packet: fd: 64 state: 1 errno: 104 vio_errno: 1160 length: 42
[ERROR] mariadbd: Got an error writing communication packets
[Warning] Aborted connection 55 to db: 'unconnected' user: 'unauthenticated' host: 'connecting host' (This connection closed normally without authentication)
[Warning] Could not read packet: fd: 64 state: 1 read_length: 4 errno: 11 vio_errno: 1158 length: 0
[Warning] Aborted connection 56 to db: 'unconnected' user: 'unauthenticated' host: '137.184.75.161' (This connection closed normally without authentication)
[Warning] Could not read packet: fd: 64 state: 1 read_length: 4 errno: 0 vio_errno: 1158 length: 0
[Warning] Aborted connection 57 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication)
[Warning] Could not read packet: fd: 87 state: 1 read_length: 4 errno: 0 vio_errno: 1158 length: 0
[Warning] Aborted connection 58 to db: 'unconnected' user: 'unauthenticated' host: '165.22.188.115' (This connection closed normally without authentication)
[Warning] Could not read packet: fd: 64 state: 1 read_length: 196974 errno: 11 vio_errno: 1158 length: 0
[Warning] Aborted connection 59 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication)
[Warning] Could not read packet: fd: 64 state: 1 read_length: 196974 errno: 11 vio_errno: 1158 length: 0
[Warning] Aborted connection 60 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication)
[Warning] Could not read packet: fd: 64 state: 1 read_length: 197053 errno: 11 vio_errno: 1158 length: 0
[Warning] Aborted connection 61 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication)
[Warning] Could not read packet: fd: 64 state: 1 read_length: 197067 errno: 11 vio_errno: 1158 length: 0
[Warning] Aborted connection 62 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication)
[Warning] Could not read packet: fd: 64 state: 1 read_length: 196986 errno: 11 vio_errno: 1158 length: 0
[Warning] Aborted connection 63 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication)
[Warning] Could not read packet: fd: 64 state: 1 read_length: 131449 errno: 11 vio_errno: 1158 length: 0
[Warning] Aborted connection 64 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication)
[Warning] Could not read packet: fd: 64 state: 1 read_length: 65900 errno: 11 vio_errno: 1158 length: 0
[Warning] Aborted connection 65 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication)
[Warning] Could not read packet: fd: 64 state: 1 read_length: 65900 errno: 11 vio_errno: 1158 length: 0
[Warning] Aborted connection 66 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication)
[Warning] Could not read packet: fd: 64 state: 1 read_length: 65910 errno: 11 vio_errno: 1158 length: 0
[Warning] Aborted connection 67 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication)
[Warning] Could not read packet: fd: 64 state: 1 read_length: 65887 errno: 11 vio_errno: 1158 length: 0
[Warning] Aborted connection 68 to db: 'unconnected' user: 'unauthenticated' host: '165.22.191.252' (This connection closed normally without authentication)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What exactly was tried in the third case is still beyond my knowledge.&lt;/p&gt;
&lt;p&gt;And here is a breakdown of the error messages:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# perror 104
OS error code 104: Connection reset by peer

# perror 11
OS error code 11: Resource temporarily unavailable

# perror 1158
MariaDB error code 1158 (ER_NET_READ_ERROR): Got an error reading communication packets
Learn more: https://mariadb.com/kb/en/e1158/

# perror 1160
MariaDB error code 1160 (ER_NET_ERROR_ON_WRITE): Got an error writing communication packets
Learn more: https://mariadb.com/kb/en/e1160/
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="out-of-order-packets-4-x"&gt;Out of order packets (4 x)&lt;/h2&gt;
&lt;p&gt;Another pattern we have seen is packets in the wrong order. Whether this is intentional or has to do with the network between the attacker and the database cannot be said at the moment (the IPs are said to originate from Italy, USA and 2 x Sweden).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;: 45.91.171.169 45.147.250.222 20.168.122.53 91.223.169.88&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ERROR] mariadbd: Got packets out of order
[Warning] Aborted connection 49 to db: 'unconnected' user: 'unauthenticated' host: '103.45.246.42' (This connection closed normally without authentication)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="incomplete-connection-setup-51-x"&gt;Incomplete connection setup (51 x)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;: 80.82.70.133 194.165.16.167 162.142.125.&lt;br&gt;* 205.210.31.&lt;br&gt;* 104.248.130.34 198.235.24.&lt;br&gt;* 209.38.99.93 171.36.7.2 34.77.151.17 118.193.33.60 147.185.132.118 88.214.25.121 188.166.68.252 118.193.43.158 206.189.5.176 165.22.187.120 45.142.193.153 196.251.90.186 134.209.221.50 89.185.82.115 104.248.229.49 35.205.56.72 198.235.24.28 43.248.108.8 167.71.184.54 154.212.141.215 89.248.174.130 154.212.141.212 34.140.35.166 167.94.146.&lt;br&gt;* 167.94.145.&lt;br&gt;* 103.149.26.234 137.184.64.140 170.64.154.53 165.22.188.115 185.47.172.136 199.45.154.148 147.185.132.108 20.171.28.254 103.203.57.18&lt;/p&gt;
&lt;p&gt;and also from these networks (Internet monitoring and AWS):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;: {larry|sharon|susan}.probe.onyphe.net {poetic|glowing|principled&lt;br&gt;].monitoring.internet-measurement.com prod-{boron|barium}-{sfo2|us-central|us-east|nyc1|us-southeast}-{&lt;br&gt;d{2,3}}. {do|li}.binaryedge.ninja azpd{&lt;br&gt;w{5,8}}.stretchoid.com scan-{&lt;br&gt;d{2}&lt;br&gt;[a-z&lt;br&gt;]}.shadowserver.org pdcscan{2,3}.scanning.cybcube.com ec2-{&lt;br&gt;w&lt;br&gt;*}&lt;br&gt;[us-east-2&lt;br&gt;]?.compute&lt;br&gt;[-1&lt;br&gt;]?.amazonaws.com&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] Aborted connection 325749 to db: 'unconnected' user: 'unauthenticated' host: '137.184.64.140' (This connection closed normally without authentication)
... 0, 1, 4, 5, 8, 9, 10 Wiederholungen
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="access-attempt-using-regular-connect"&gt;Access attempt using regular connect&lt;/h2&gt;
&lt;h3 id="attempts-without-password-40x"&gt;Attempts WITHOUT password (40x)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;: 196.251.91.&lt;br&gt;* 196.251.114.&lt;br&gt;* 196.251.90.&lt;br&gt;* 196.251.115.18 196.251.115.26 196.251.83.97 196.251. 90.186 34.140.170.97 196.251.85.11 196.251.83.125&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] Access denied for user 'root'@'196.251.91.69' (using password: NO)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="attempts-without-and-then-with-password-28-x"&gt;Attempts WITHOUT and then WITH password (28 x)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;: 165.154.172.87 165.154.164.92 128.14.237.43 196.251.69.185 37.19.221.171 196.251.118.8 196.251.91.&lt;br&gt;* 196.251.118.47 45.129.56.161 146.70.132.164 196.251.86.26 196.251.83.136 38.240.225.39&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] Access denied for user 'root'@'196.251.80.168' (using password: NO)
[Warning] Access denied for user 'root'@'196.251.80.168' (using password: YES)
... 1, 2, 3, 13, 27, 28, 37 Wiederholungen
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="more-complex-access-attempts-using-port-probing-and-regular-connect-15-x"&gt;More complex access attempts using port probing and regular connect (15 x)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;: 8.219.222.66 47.250.81.7 8.219.222.66 34.76.203.56 8.221.136.6 47.254.192.213 (6 x)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] Aborted connection 1134 to db: 'unconnected' user: 'unauthenticated' host: '47.254.192.213' (This connection closed normally without authentication)
[Warning] Access denied for user 'root'@'47.254.192.213' (using password: NO)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Source: 45.150.237.21 (1 x)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] Aborted connection 22965 to db: 'unconnected' user: 'unauthenticated' host: '45.150.237.21' (This connection closed normally without authentication)
... 9 Wiederholungen
[Warning] Access denied for user ''@'45.150.237.21' (using password: NO)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;: 101.36.122.183 152.32.150.7 152.32.245.170 118.193.58.125 165.154.48.24 107.150.117.219 116.90.238.220 165.154.100.58 (8 x)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] Aborted connection 2816 to db: 'unconnected' user: 'unauthenticated' host: '165.154.100.58' (This connection closed normally without authentication)
... 0, 1 Wiederholungen
[Warning] Access denied for user ''@'165.154.100.58' (using password: NO)
[Warning] Access denied for user 'root'@'165.154.100.58' (using password: YES)
... 0, 48 Widerholungen
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="more-complex-access-attempts-using-regular-connect-and-port-probing-3-x"&gt;More complex access attempts using regular connect and port probing (3 x)&lt;/h2&gt;
&lt;p&gt;Source: 104.193.135.104 (1 x)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] Access denied for user 'root'@'104.193.135.104' (using password: NO)
[Warning] Aborted connection 47 to db: 'unconnected' user: 'unauthenticated' host: '104.193.135.104' (This connection closed normally without authentication)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Source: 196.251.91.18 (1 x)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] Access denied for user 'root'@'196.251.91.18' (using password: NO)
[Warning] Access denied for user 'root'@'196.251.91.18' (using password: YES)
... 3 Wiederholungen
[Warning] Aborted connection 1013 to db: 'unconnected' user: 'unauthenticated' host: '196.251.91.18' (This connection closed normally without authentication)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Source: 94.102.49.155 (1 x)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Warning] Access denied for user 'root'@'94.102.49.155' (using password: NO)
[Warning] Access denied for user 'root'@'94.102.49.155' (using password: YES)
... 1 Wiederholungen
[Warning] Aborted connection 1389 to db: 'unconnected' user: 'unauthenticated' host: '94.102.49.155' (This connection closed normally without authentication)
[Warning] Access denied for user 'root'@'94.102.49.155' (using password: YES)
... 3 Wiederholungen
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These patterns rarely occurred in the observed period.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Paying a ransom for cybercrime is not worth it!&lt;/p&gt;
&lt;h2 id="outlook--todoes"&gt;Outlook / Todoes&lt;/h2&gt;
&lt;p&gt;Further points that could be clarified, refined and optimised next time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Find out which passwords are being tried. Maybe patch MariaDB? (&lt;code&gt;sql_acl.cc&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Provide some more exciting data and see what exactly happens.&lt;/li&gt;
&lt;li&gt;Record several different attacks (filtered for IP?). Possibly from different countries (USA, China, Russia, Ukraine, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;You could also try running the honeypot with &lt;code&gt;skip_grant_tables&lt;/code&gt; to enable access with a password?&lt;/li&gt;
&lt;li&gt;log_warnings is set too verbose with 9. Maybe the default is enough?&lt;/li&gt;
&lt;li&gt;Access with SSL only? See if someone already knows TLS.&lt;/li&gt;
&lt;li&gt;Galera protocol? Was this really an attack or just a problem in the network/with the Galera cluster?&lt;/li&gt;
&lt;li&gt;Play the same game with MySQL to see if there are other attack patterns.&lt;/li&gt;
&lt;li&gt;Which other DB users are being attacked (CMS)?&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>How does Galera Cluster behave with many nodes?</title><link>https://www.fromdual.com/blog/how-does-galera-cluster-behave-with-many-nodes/</link><pubDate>Fri, 24 Jan 2025 18:12:55 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/how-does-galera-cluster-behave-with-many-nodes/</guid><description>&lt;p&gt;Recently I had the opportunity to have a lot of Linux systems (VMs with Rocky Linux 9) from one of our regular &lt;a href="https://www.fromdual.com/galera-cluster-for-mysql-mariadb-training" title="Overview of FromDual Galera Cluster Training"&gt;Galera Cluster trainings&lt;/a&gt; all to myself for a week. And MariaDB 11.4.4 with Galera Cluster was already installed on the machines.&lt;/p&gt;
&lt;p&gt;Since I had long wanted to try out how a Galera Cluster behaves with an increasing number of nodes, now was the opportunity to try it out.&lt;/p&gt;
&lt;p&gt;The following questions were to be answered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How does the throughput of a Galera cluster behave depending on the number of Galera nodes?&lt;/li&gt;
&lt;li&gt;Which configuration gives us the highest throughput?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A total of 5 different test parameters were experimented with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Number of Galera nodes.&lt;/li&gt;
&lt;li&gt;Number of client machines (= instances).&lt;/li&gt;
&lt;li&gt;Number of threads per client (&lt;code&gt;--threads=&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Number of Galera threads (&lt;code&gt;wsrep_slave_threads&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Runtime of the tests. This parameter was varied because some tests were cancelled during the run. It may be possible to eliminate this parameter with a lower rate (&lt;code&gt;--rate&lt;/code&gt;) in the load test. As it turned out, it did have an influence on the result or the measured throughput (e.g. test 4b and 5 or 18 and 19).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A total of 35 different tests were run. See &lt;a href="https://www.fromdual.com/blog/how-does-galera-cluster-behave-with-many-nodes/#raw-data"&gt;raw data&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="throughput-as-a-function-of-the-number-of-galera-nodes"&gt;Throughput as a function of the number of Galera nodes&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://www.fromdual.com/sites/default/files/galera_node_scaling_graph1.png" alt="graph"&gt;&lt;/p&gt;
&lt;table&gt;
&lt;caption&gt;Throughput related to # nodes&lt;/caption&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;# gal nodes&lt;/th&gt;
&lt;th&gt;# threads/client&lt;/th&gt;
&lt;th&gt;runtime [s]&lt;/th&gt;
&lt;th&gt;tps&lt;/th&gt;
&lt;th&gt;runtime [s]&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;7&lt;/th&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;td&gt;596.3&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;8&lt;/th&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;td&gt;567.8&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;9&lt;/th&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;td&gt;531.9&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;11&lt;/th&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;td&gt;495.2&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;12&lt;/th&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;td&gt;492.2&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;13&lt;/th&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;td&gt;502.9&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;14&lt;/th&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;td&gt;459.5&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;15&lt;/th&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;td&gt;458.6&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;16&lt;/th&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;td&gt;429.2&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Throughput related to &lt;br&gt;# nodes&lt;/p&gt;
&lt;p&gt;The throughput in the Galera cluster decreased slightly from 600 tps to 430 tps (28%) when the number of nodes was increased from 1 to 9.&lt;/p&gt;
&lt;h2 id="throughput-as-a-function-of-the-number-of-connections"&gt;Throughput as a function of the number of connections&lt;/h2&gt;
&lt;p&gt;The main variation here was with the number of clients and threads per client. The optimum seems to be 30 - 40 connections in this setup. Varying the number of Galera threads (&lt;code&gt;wsrep_slave_threads&lt;/code&gt;) does not seem to have had much effect in our case. The system does not seem to be able to deliver much more than 1200 tps. In particular, the machines of the described Galera nodes did not have too much CPU idle time.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.fromdual.com/sites/default/files/galera_node_scaling_graph2.png" alt="graph"&gt;&lt;/p&gt;
&lt;table&gt;
&lt;caption&gt;Total # connections vs. throughput&lt;/caption&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;# client nodes&lt;/th&gt;
&lt;th&gt;# threads/client&lt;/th&gt;
&lt;th&gt;# con tot&lt;/th&gt;
&lt;th&gt;# gal threads&lt;/th&gt;
&lt;th&gt;runtime [s]&lt;/th&gt;
&lt;th&gt;tps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;16&lt;/th&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;td&gt;429.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;17&lt;/th&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;td&gt;684.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;18&lt;/th&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;180&lt;/td&gt;
&lt;td&gt;603.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;19&lt;/th&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;925.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;20&lt;/th&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;919.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;21&lt;/th&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;1081.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;22&lt;/th&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;1196.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;23&lt;/th&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;1132.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;23b&lt;/th&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;1106.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;24&lt;/th&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;1233.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;25&lt;/th&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;160&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;120&lt;/td&gt;
&lt;td&gt;1095.7&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Total &lt;br&gt;# connections vs. throughput&lt;/p&gt;
&lt;h2 id="throughput-as-a-function-of-all-possible-parameters"&gt;Throughput as a function of all possible parameters&lt;/h2&gt;
&lt;p&gt;By further varying the parameters, in particular by reducing the number of Galera nodes from 9 to 3, the throughput could be further increased from just under 1200 to just over 1400 tps.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.fromdual.com/sites/default/files/galera_node_scaling_graph3.png" alt="graph"&gt;&lt;/p&gt;
&lt;table&gt;
&lt;caption&gt;Throughput related to various different parameters&lt;/caption&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;# gal nodes&lt;/th&gt;
&lt;th&gt;# client nodes&lt;/th&gt;
&lt;th&gt;# threads/client&lt;/th&gt;
&lt;th&gt;# con tot&lt;/th&gt;
&lt;th&gt;tps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;23&lt;/th&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;1132.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;23b&lt;/th&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;1106.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;24&lt;/th&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;1233.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;25&lt;/th&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;160&lt;/td&gt;
&lt;td&gt;1095.7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;26&lt;/th&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;160&lt;/td&gt;
&lt;td&gt;1132.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;27&lt;/th&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;160&lt;/td&gt;
&lt;td&gt;1207.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;28&lt;/th&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;td&gt;1333.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;29&lt;/th&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;1278.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;30&lt;/th&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;1281.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;31&lt;/th&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;1374.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;32&lt;/th&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;1304.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;33&lt;/th&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;48&lt;/td&gt;
&lt;td&gt;1428.9&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Throughput related to various different parameters&lt;/p&gt;
&lt;p&gt;With the given hardware, there seems to be an optimum somewhere around 3 Galera nodes and approx. 40 connections. More detailed clarifications would be interesting here&amp;hellip;&lt;/p&gt;
&lt;h2 id="statistical-design-of-experiments-doe"&gt;Statistical Design of Experiments (DoE)&lt;/h2&gt;
&lt;p&gt;Here it would be exciting to work with the method of statistical design of experiments to determine this optimum more precisely or to find it more quickly.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mettler Toledo: &lt;a href="https://www.mt.com/de/de/home/applications/L1_AutoChem_Applications/L2_ReactionAnalysis/design-of-experiments-doe.html" target="_blank"&gt;DoE - Statistical Design of Experiments&lt;/a&gt; - A statistical approach to reaction optimisation.&lt;/li&gt;
&lt;li&gt;Wikipedia.en:
Statistical design of experiments..&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatab.de/tutorial/design-of-experiments" target="_blank"&gt;Design of Experiments - DoE&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Novustat: &lt;a href="https://novustat.com/statistik-blog/quality-engineering-statistische-versuchsplanung-unser-ultimativer-ueberblick.html" target="_blank"&gt;Quality Engineering: Statistical Design of Experiments - Our ultimate overview!&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="hardware-specification"&gt;Hardware specification&lt;/h2&gt;
&lt;p&gt;VM&amp;rsquo;s from Hetzner: CX22 (2 vCPU, 4 Gibyte RAM (effective: 3.5 Gibyte (why that?)), 40 Gibyte disc)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Architecture: x86_64
 CPU op-mode(s): 32-bit, 64-bit
 Address sizes: 40 bits physical, 48 bits virtual
 Byte Order: Little Endian
CPU(s): 2
 On-line CPU(s) list: 0,1
Vendor ID: GenuineIntel
 BIOS Vendor ID: QEMU
 Model name: Intel Xeon Processor (Skylake, IBRS, no TSX)
 BIOS Model name: NotSpecified
 CPU family: 6
 Model: 85
 Thread(s) per core: 1
 Core(s) per socket: 2
 Socket(s): 1
 Stepping: 4
 BogoMIPS: 4589.21
 Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2a
 pic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault pti ssbd ibrs ibpb fsgsbase bmi1 avx2 smep bmi2 erms invpcid avx512f avx512dq rdseed adx smap clwb avx512cd avx512bw avx512vl xs
 aveopt xsavec xgetbv1 xsaves arat pku ospke md_clear
Virtualization features:
 Hypervisor vendor: KVM
 Virtualization type: full
Caches (sum of all):
 L1d: 64 KiB (2 instances)
 L1i: 64 KiB (2 instances)
 L2: 8 MiB (2 instances)
 L3: 16 MiB (1 instance)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="benchmark-tool--load-generator"&gt;Benchmark tool / load generator&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;sysbench&lt;/code&gt; was used as a load generator.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# dnf install epel-release
# dnf install sysbench
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each client runs on its own scheme to avoid Galera cluster conflicts. In reality, this is not always the case, but it is the optimal case for Galera.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; CREATE DATABASE sbtest&amp;lt;n&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each client connects to a different Galera node (1 - 6 clients distributed on 1 - 9 Galera nodes).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GALERA_IP=&amp;lt;galera_ip&amp;gt;
DATABASE=sbtest&amp;lt;n&amp;gt;

# sysbench oltp_common --mysql-host=${GALERA_IP} --mysql-user=app --mysql-password=secret --mysql-db=${DATABASE} --db-driver=mysql prepare
# sysbench oltp_read_write --time=180 --db-driver=mysql --mysql-host=${GALERA_IP} --mysql-user=app --mysql-password=secret --mysql-db=${DATABASE} --threads=8 --rate=1000 --report-interval=1 run
# sysbench oltp_common --mysql-host=${GALERA_IP} --mysql-user=app --mysql-password=secret --mysql-db=${DATABASE} --db-driver=mysql cleanup
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="mariadb-and-galera-configuration"&gt;MariaDB and Galera configuration&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;[server]

binlog_format = row
innodb_autoinc_lock_mode = 2
innodb_flush_log_at_trx_commit = 2
query_cache_size = 0
query_cache_type = 0

wsrep_on = on
wsrep_provider = /usr/lib64/galera-4/libgalera_smm.so
wsrep_cluster_address = &amp;quot;gcomm://10.0.0.2,10.0.0.3,10.0.0.4,10.0.0.5,10.0.0.6,10.0.0.7,10.0.0.8,10.0.0.9,10.0.0.10,10.0.0.11,10.0.0.12,10.0.0.13,10.0.0.14,10.0.0.15,10.0.0.16,10.0.0.17&amp;quot;
wsrep_cluster_name = 'Galera Cluster'
wsrep_node_address = 10.0.0.2
wsrep_sst_method = rsync
wsrep_sst_auth = sst:secret
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="raw-data"&gt;Raw data&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/sites/default/files/galera_node_scaling_raw_data.tar.gz"&gt;Raw data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Processed data&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Model v2 slightly improves results</title><link>https://www.fromdual.com/blog/playing-with-mariadb-vector-for-initial-ai-tests/comment-1065/</link><pubDate>Wed, 28 Aug 2024 15:55:43 +0200</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/playing-with-mariadb-vector-for-initial-ai-tests/comment-1065/</guid><description>&lt;p&gt;We have improved our model (&lt;a href="https://www.fromdual.com/sites/default/files/fromdual_llm_v2.phpx"&gt;see v2&lt;/a&gt;) so the results are a bit better/more accurate now.&lt;/p&gt;
&lt;p&gt;For usage see &lt;code&gt;./fromdual_llm_v2.php --help&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Playing with MariaDB Vector for initial AI tests</title><link>https://www.fromdual.com/blog/playing-with-mariadb-vector-for-initial-ai-tests/</link><pubDate>Wed, 28 Aug 2024 10:51:23 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/playing-with-mariadb-vector-for-initial-ai-tests/</guid><description>&lt;p&gt;Artificial intelligence (AI) and vector databases are on everyone&amp;rsquo;s lips these days. Since MariaDB will soon be coming onto the market with vector database functionality, as a database consultant I thought it was about time I got to grips with the subject so that I have at least a hint of what it&amp;rsquo;s all about&amp;hellip;&lt;/p&gt;
&lt;p&gt;Since I&amp;rsquo;m not so much of a theoretician but rather like to do something practical, I&amp;rsquo;ve built a small &amp;ldquo;AI&amp;rdquo; prototype that anyone can build very quickly and easily on their laptop (without a GPU)&amp;hellip;&lt;/p&gt;
&lt;p&gt;I also took the liberty of stealing the graphs from the MariaDB Foundation presentation (see sources at the end).&lt;/p&gt;
&lt;h2 id="downloading-the-mariadb-database-with-vector-functionality"&gt;Downloading the MariaDB database with vector functionality&lt;/h2&gt;
&lt;p&gt;There are no MariaDB packages with vector functionality yet, but the &lt;a href="https://mariadb.org/download/?t=mariadb&amp;amp;p=mariadb&amp;amp;r=11.6.0+Vector&amp;amp;os=source" target="_blank" title="MariaDB Vector source code"&gt;source code&lt;/a&gt; is already available. So you can quickly build the binaries yourself. This took just under an hour on my old box. Once the binaries are built, you can make a tarball out of them:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# tar xf mariadb-11.6.0_vector.tar.gz
# cd mariadb-11.6.0_vector/
# cmake .
# make
# make package
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The MariaDB database then only needs to be started.&lt;/p&gt;
&lt;h2 id="the-model"&gt;The model&lt;/h2&gt;
&lt;p&gt;To show the concept of tokenisation I decided to build an AI for URLs and to show the concept of different models and their potential for improvement I built a very stupid model in PHP, which simply decomposes a URL.&lt;/p&gt;
&lt;p&gt;The question that this model should be able to answer is: &amp;ldquo;Give me similar URLs to the following URL.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The corresponding table looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DROP TABLE IF EXISTS `urls`;
-- TRUNCATE TABLE is NOT sufficient!!!
CREATE TABLE `urls` (
 `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
, `url` varchar(1024) DEFAULT NULL
, `title` varchar(2000) DEFAULT NULL
, `embedding` blob NOT NULL
, VECTOR KEY `embedding` (`embedding`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The model &lt;code&gt;fromdual_llm_v1&lt;/code&gt; can be downloaded &lt;a href="https://www.fromdual.com/sites/default/files/fromdual_llm_v1.phpx"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This diagram from the MariaDB Foundation shows roughly how the whole thing works:&lt;/p&gt;
&lt;img src="https://www.fromdual.com/sites/default/files/vector_1.png" width="640" /&gt;
&lt;h2 id="training-the-ai"&gt;Training the AI&lt;/h2&gt;
&lt;p&gt;The database is then trained: The URL is taken as given and the title can be read out using an HTML scraper, for example. Here are 8 training datasets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mariadb.org/download/?t=mariadb&amp;amp;p=mariadb&amp;amp;r=11.6.0+Vector&amp;amp;os=source" target="_blank"&gt;Download MariaDB Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/creating-the-mariadb-binary-tarball/" target="_blank"&gt;Creating the MariaDB Binary Tarball&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.org/wp-content/uploads/2024/02/MariaDB-Vector.pdf" target="_blank"&gt;MariaDB Vector&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/resources/blog/mariadb-vector-preview-is-out/" target="_blank"&gt;MariaDB Vector preview is out&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.org/projects/mariadb-vector/" target="_blank"&gt;MariaDB Vector&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://metacpan.org/pod/Perl::Tokenizer" target="_blank"&gt;Perl::Tokenizer - A tiny Perl code tokenizer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.qwak.com/post/utilizing-llms-with-embedding-stores" target="_blank"&gt;Integrating Vector Databases with LLMs: A Hands-On Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/qwak-ai/qwak-examples/tree/main/qa_bot_falcon_chroma" target="_blank"&gt;LLM Model Enhanced with Vector DB&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The vectors are then generated using our model:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(./fromdual_llm_v1.php https://mariadb.org/download/?t=mariadb&amp;amp;p=mariadb&amp;amp;r=11.6.0+Vector&amp;amp;os=source
./fromdual_llm_v1.php https://mariadb.com/kb/en/creating-the-mariadb-binary-tarball/
./fromdual_llm_v1.php https://mariadb.org/wp-content/uploads/2024/02/MariaDB-Vector.pdf
./fromdual_llm_v1.php https://mariadb.com/resources/blog/mariadb-vector-preview-is-out/
./fromdual_llm_v1.php https://mariadb.org/projects/mariadb-vector/
./fromdual_llm_v1.php https://metacpan.org/pod/Perl::Tokenizer
./fromdual_llm_v1.php https://www.qwak.com/post/utilizing-llms-with-embedding-stores
./fromdual_llm_v1.php https://github.com/qwak-ai/qwak-examples/tree/main/qa_bot_falcon_chroma) | grep '^&amp;lt;br&amp;gt;['
[0.2, 0.0107421875, 0, 0, 0, 0.0006103515625, 0.00054931640625, 0]
[0.2, 0.0107421875, 0, 0, 0, 0.00262451171875, 0, 0]
[0.2, 0.0107421875, 0, 0, 0, 0.0028076171875, 0, 0]
[0.2, 0.0107421875, 0, 0, 0, 0.0028076171875, 0, 0]
[0.2, 0.0107421875, 0, 0, 0, 0.00152587890625, 0, 0]
[0.2, 0.01171875, 0, 0, 0, 0.001220703125, 0, 0]
[0.2, 0.01171875, 0, 0, 0, 0.0025634765625, 0, 0]
[0.2, 0.009765625, 0, 0, 0, 0.00323486328125, 0, 0]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The database is now fed (trained) with these vectors:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;INSERT INTO `urls` (id, url, title, embedding) VALUES (
 NULL
, 'https://mariadb.org/download/?t=mariadb&amp;amp;p=mariadb&amp;amp;r=11.6.0+Vector&amp;amp;os=source'
, 'Download MariaDB Server'
, VEC_FromText('[0.2, 0.0107421875, 0, 0, 0, 0.00262451171875, 0, 0]')
);

INSERT INTO `urls` (id, url, title, embedding) VALUES (
 NULL
, 'https://mariadb.com/kb/en/creating-the-mariadb-binary-tarball/'
, 'Creating the MariaDB Binary Tarball'
, VEC_FromText('[0.2, 0.0107421875, 0, 0, 0, 0.0006103515625, 0.00054931640625, 0]')
);

INSERT INTO `urls` (id, url, title, embedding) VALUES (
 NULL
, 'https://mariadb.org/wp-content/uploads/2024/02/MariaDB-Vector.pdf'
, 'MariaDB Vector'
, VEC_FromText('[0.2, 0.0107421875, 0, 0, 0, 0.0028076171875, 0, 0]')
);

INSERT INTO `urls` (id, url, title, embedding) VALUES (
 NULL
, 'https://mariadb.com/resources/blog/mariadb-vector-preview-is-out/'
, 'MariaDB Vector preview is out'
, VEC_FromText('[0.2, 0.0107421875, 0, 0, 0, 0.0028076171875, 0, 0]')
);

INSERT INTO `urls` (id, url, title, embedding) VALUES (
 NULL
, 'https://mariadb.org/projects/mariadb-vector/'
, 'MariaDB Vector'
, VEC_FromText('[0.2, 0.0107421875, 0, 0, 0, 0.00152587890625, 0, 0]')
);

INSERT INTO `urls` (id, url, title, embedding) VALUES (
 NULL
, 'https://metacpan.org/pod/Perl::Tokenizer'
, 'Perl::Tokenizer - A tiny Perl code tokenizer'
, VEC_FromText('[0.2, 0.01171875, 0, 0, 0, 0.001220703125, 0, 0]')
);

INSERT INTO `urls` (id, url, title, embedding) VALUES (
 NULL
, 'https://www.qwak.com/post/utilizing-llms-with-embedding-stores'
, 'Integrating Vector Databases with LLMs: A Hands-On Guide'
, VEC_FromText('[0.2, 0.01171875, 0, 0, 0, 0.0025634765625, 0, 0]')
);

INSERT INTO `urls` (id, url, title, embedding) VALUES (
 NULL
, 'https://github.com/qwak-ai/qwak-examples/tree/main/qa_bot_falcon_chroma'
, 'LLM Model Enhanced with Vector DB'
, VEC_FromText('[0.2, 0.009765625, 0, 0, 0, 0.00323486328125, 0, 0]')
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is an overview of what is now in the database:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT id, url, title, VEC_ToText(embedding)
 FROM urls
;
+----+-----------------------------------------------------------------------------+----------------------------------------------------------+---------------------------------------------------------------------------+
| id | url | title | VEC_ToText(embedding) |
+----+-----------------------------------------------------------------------------+----------------------------------------------------------+---------------------------------------------------------------------------+
| 1 | https://mariadb.org/download/?t=mariadb&amp;amp;p=mariadb&amp;amp;r=11.6.0+Vector&amp;amp;os=source | Download MariaDB Server | [0.200000,0.010742,0.000000,0.000000,0.000000,0.002625,0.000000,0.000000] |
| 2 | https://mariadb.com/kb/en/creating-the-mariadb-binary-tarball/ | Creating the MariaDB Binary Tarball | [0.200000,0.010742,0.000000,0.000000,0.000000,0.000610,0.000549,0.000000] |
| 3 | https://mariadb.org/wp-content/uploads/2024/02/MariaDB-Vector.pdf | MariaDB Vector | [0.200000,0.010742,0.000000,0.000000,0.000000,0.002808,0.000000,0.000000] |
| 4 | https://mariadb.com/resources/blog/mariadb-vector-preview-is-out/ | MariaDB Vector preview is out | [0.200000,0.010742,0.000000,0.000000,0.000000,0.002808,0.000000,0.000000] |
| 5 | https://mariadb.org/projects/mariadb-vector/ | MariaDB Vector | [0.200000,0.010742,0.000000,0.000000,0.000000,0.001526,0.000000,0.000000] |
| 6 | https://metacpan.org/pod/Perl::Tokenizer | Perl::Tokenizer - A tiny Perl code tokenizer | [0.200000,0.011719,0.000000,0.000000,0.000000,0.001221,0.000000,0.000000] |
| 7 | https://www.qwak.com/post/utilizing-llms-with-embedding-stores | Integrating Vector Databases with LLMs: A Hands-On Guide | [0.200000,0.011719,0.000000,0.000000,0.000000,0.002563,0.000000,0.000000] |
| 8 | https://github.com/qwak-ai/qwak-examples/tree/main/qa_bot_falcon_chroma | LLM Model Enhanced with Vector DB | [0.200000,0.009766,0.000000,0.000000,0.000000,0.003235,0.000000,0.000000] |
+----+-----------------------------------------------------------------------------+----------------------------------------------------------+---------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="search-in-the-mariadb-vector-database"&gt;Search in the MariaDB vector database&lt;/h2&gt;
&lt;p&gt;Now comes the exciting part of the whole story: Can we also find something in our MariaDB vector database with URLs?&lt;/p&gt;
&lt;p&gt;How this works schematically can again be seen in the MariaDB Foundation diagram:&lt;/p&gt;
&lt;img src="https://www.fromdual.com/sites/default/files/vector_2.png" width="640" /&gt;
&lt;p&gt;The first attempt is a perfect match:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./fromdual_llm_v1.php https://mariadb.org/projects/mariadb-vector/
[0.2, 0.0107421875, 0, 0, 0, 0.00152587890625, 0, 0]

SELECT id, url, title, VEC_ToText(embedding)
 FROM urls
 ORDER BY VEC_DISTANCE(embedding, VEC_FromText('[0.2, 0.0107421875, 0, 0, 0, 0.00152587890625, 0, 0]'))
LIMIT 3
;
+----+----------------------------------------------------------------+-----------------------------------------------+---------------------------------------------------------------------------+
| id | url | title | VEC_ToText(embedding) |
+----+----------------------------------------------------------------+-----------------------------------------------+---------------------------------------------------------------------------+
| 5 | https://mariadb.org/projects/mariadb-vector/ | MariaDB Vector | [0.200000,0.010742,0.000000,0.000000,0.000000,0.001526,0.000000,0.000000] |
| 6 | https://metacpan.org/pod/Perl::Tokenizer | Perl::Tokenizer - A tiny Perl code tokenizer. | [0.200000,0.011719,0.000000,0.000000,0.000000,0.001221,0.000000,0.000000] |
| 2 | https://mariadb.com/kb/en/creating-the-mariadb-binary-tarball/ | Creating the MariaDB Binary Tarball | [0.200000,0.010742,0.000000,0.000000,0.000000,0.000610,0.000549,0.000000] |
+----+----------------------------------------------------------------+-----------------------------------------------+---------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first row matches 100%. Then the results get much worse relatively quickly&amp;hellip;&lt;/p&gt;
&lt;p&gt;Second attempt a similar URL:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./fromdual_llm_v1.php https://mariadb.com/kb/en/e4201/
[0.2, 0.0107421875, 0, 0, 0, 0.00079345703125, 0, 0]

SELECT id, url, title, VEC_ToText(embedding)
 FROM urls
 ORDER BY VEC_DISTANCE(embedding, VEC_FromText('[0.2, 0.0107421875, 0, 0, 0, 0.00079345703125, 0, 0]'))
LIMIT 3
;
+----+----------------------------------------------------------------+-----------------------------------------------+---------------------------------------------------------------------------+
| id | url | title | VEC_ToText(embedding) |
+----+----------------------------------------------------------------+-----------------------------------------------+---------------------------------------------------------------------------+
| 2 | https://mariadb.com/kb/en/creating-the-mariadb-binary-tarball/ | Creating the MariaDB Binary Tarball | [0.200000,0.010742,0.000000,0.000000,0.000000,0.000610,0.000549,0.000000] |
| 5 | https://mariadb.org/projects/mariadb-vector/ | MariaDB Vector | [0.200000,0.010742,0.000000,0.000000,0.000000,0.001526,0.000000,0.000000] |
| 6 | https://metacpan.org/pod/Perl::Tokenizer | Perl::Tokenizer - A tiny Perl code tokenizer. | [0.200000,0.011719,0.000000,0.000000,0.000000,0.001221,0.000000,0.000000] |
+----+----------------------------------------------------------------+-----------------------------------------------+---------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here I would expect only mariadb URLs among the first 3 hits. But this is not the case. So our model still has room for improvement here!&lt;/p&gt;
&lt;p&gt;And another similar URL:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./fromdual_llm_v1.php https://mariadb.com/kb/en/vec_totext/
[0.2, 0.0107421875, 0, 0, 0, 0.0010986328125, 0, 0]

SELECT id, url, title, VEC_ToText(embedding)
 FROM urls
 ORDER BY VEC_DISTANCE(embedding, VEC_FromText('[0.2, 0.0107421875, 0, 0, 0, 0.0010986328125, 0, 0]'))
LIMIT 3
;
+----+----------------------------------------------------------------+-----------------------------------------------+---------------------------------------------------------------------------+
| id | url | title | VEC_ToText(embedding) |
+----+----------------------------------------------------------------+-----------------------------------------------+---------------------------------------------------------------------------+
| 5 | https://mariadb.org/projects/mariadb-vector/ | MariaDB Vector | [0.200000,0.010742,0.000000,0.000000,0.000000,0.001526,0.000000,0.000000] |
| 2 | https://mariadb.com/kb/en/creating-the-mariadb-binary-tarball/ | Creating the MariaDB Binary Tarball | [0.200000,0.010742,0.000000,0.000000,0.000000,0.000610,0.000549,0.000000] |
| 6 | https://metacpan.org/pod/Perl::Tokenizer | Perl::Tokenizer - A tiny Perl code tokenizer. | [0.200000,0.011719,0.000000,0.000000,0.000000,0.001221,0.000000,0.000000] |
+----+----------------------------------------------------------------+-----------------------------------------------+---------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Same problem here. The hostname is not weighted enough. You can/must probably play with the scatter that &lt;code&gt;mariadb.org&lt;/code&gt; and &lt;code&gt;mariadb.com&lt;/code&gt; generate.&lt;/p&gt;
&lt;p&gt;And last but not least, a URL that does not appear in the data set at all:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./fromdual_llm_v1.php https://www.mongodb.com/blog/post/vector-search-llm-essentials-what-when-why
[0.2, 0.0146484375, 0, 0, 0, 0.00323486328125, 0, 0]
SELECT id, url, title, VEC_ToText(embedding)
 FROM urls
 ORDER BY VEC_DISTANCE(embedding, VEC_FromText('[0.2, 0.0146484375, 0, 0, 0, 0.00323486328125, 0, 0]'))
LIMIT 5
;
+----+-----------------------------------------------------------------------------+----------------------------------------------------------+---------------------------------------------------------------------------+
| id | url | title | VEC_ToText(embedding) |
+----+-----------------------------------------------------------------------------+----------------------------------------------------------+---------------------------------------------------------------------------+
| 7 | https://www.qwak.com/post/utilizing-llms-with-embedding-stores | Integrating Vector Databases with LLMs: A Hands-On Guide | [0.200000,0.011719,0.000000,0.000000,0.000000,0.002563,0.000000,0.000000] |
| 6 | https://metacpan.org/pod/Perl::Tokenizer | Perl::Tokenizer - A tiny Perl code tokenizer. | [0.200000,0.011719,0.000000,0.000000,0.000000,0.001221,0.000000,0.000000] |
| 3 | https://mariadb.org/wp-content/uploads/2024/02/MariaDB-Vector.pdf | MariaDB Vector | [0.200000,0.010742,0.000000,0.000000,0.000000,0.002808,0.000000,0.000000] |
| 4 | https://mariadb.com/resources/blog/mariadb-vector-preview-is-out/ | MariaDB Vector preview is out | [0.200000,0.010742,0.000000,0.000000,0.000000,0.002808,0.000000,0.000000] |
| 1 | https://mariadb.org/download/?t=mariadb&amp;amp;p=mariadb&amp;amp;r=11.6.0+Vector&amp;amp;os=source | Download MariaDB Server | [0.200000,0.010742,0.000000,0.000000,0.000000,0.002625,0.000000,0.000000] |
+----+-----------------------------------------------------------------------------+----------------------------------------------------------+---------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here the result seems to be completely arbitrary. But if you compare the vector of the query with the vectors of the results, the order makes sense&amp;hellip; Are the dimensions in the vector evaluated from left to right? After all, the distance between two points in 8-dimensional space is to be determined&amp;hellip;&lt;/p&gt;
&lt;h2 id="improvements-in-the-model"&gt;Improvements in the model&lt;/h2&gt;
&lt;p&gt;The results of our AI are not yet particularly impressive. On the one hand, this is certainly due to the very limited amount of data, on the other hand, we have not yet modelled very important criteria in our model or have used completely nonsensical criteria.&lt;/p&gt;
&lt;p&gt;Suggestions for improvement for a next model: The &lt;code&gt;hostname&lt;/code&gt; could also be tokenised so that &lt;code&gt;mariadb.com&lt;/code&gt; and &lt;code&gt;mariadb.org&lt;/code&gt; are closer together.&lt;/p&gt;
&lt;p&gt;The length of &lt;code&gt;hostname&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;, &lt;code&gt;query&lt;/code&gt; and &lt;code&gt;fragment&lt;/code&gt; is certainly not a particularly clever criterion for mapping the similarity of URLs. Much more intelligence would be needed in the model here. A function &lt;code&gt;1/CRC32(dim)&lt;/code&gt; might already provide slightly better results?&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;title&lt;/code&gt; could be included, or at least the most important words (nouns, verbs) from the title.&lt;/p&gt;
&lt;p&gt;The document type (MIME type) could be included: Is a PDF more similar to another PDF than to a CSV file or a static HMTL page or a dynamic PHP page?&lt;/p&gt;
&lt;h2 id="points-that-stood-out-while-playing"&gt;Points that stood out while playing&lt;/h2&gt;
&lt;p&gt;The number of dimensions in a vector seem to be set on the first &lt;code&gt;INSERT&lt;/code&gt;. If you subsequently enter data with a different vector length, the following error appears:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;INSERT INTO products (name, description, embedding) VALUES (
 'Coffee Machine'
, 'Built to make the best coffee you can imagine'
, VEC_FromText('[0.2, 0.013671875, 0, 0, 0, 6.103515625E-5, 0, 0]')
);
ERROR 1366 (22007): Incorrect vector value: '...' for column `test`.`products`.`embedding` at row 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Changing the vector length is currently NOT possible with a &lt;code&gt;TRUNCATE TABLE&lt;/code&gt; command. The table must be dropped (&lt;code&gt;DROP TABLE&lt;/code&gt;) and created again (&lt;code&gt;CREATE TABLE&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;However, searching with a shorter vector is possible:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT id, url, title, VEC_ToText(embedding)
 FROM urls
 ORDER BY VEC_DISTANCE(embedding, VEC_FromText('[0.2, 0.0107421875]'))
LIMIT 3
;
+----+-------------------------------------------------------------------------+-------------------------------------+---------------------------------------------------------------------------+
| id | url | title | VEC_ToText(embedding) |
+----+-------------------------------------------------------------------------+-------------------------------------+---------------------------------------------------------------------------+
| 8 | https://github.com/qwak-ai/qwak-examples/tree/main/qa_bot_falcon_chroma | LLM Model Enhanced with Vector DB | [0.200000,0.009766,0.000000,0.000000,0.000000,0.003235,0.000000,0.000000] |
| 2 | https://mariadb.com/kb/en/creating-the-mariadb-binary-tarball/ | Creating the MariaDB Binary Tarball | [0.200000,0.010742,0.000000,0.000000,0.000000,0.000610,0.000549,0.000000] |
| 5 | https://mariadb.org/projects/mariadb-vector/ | MariaDB Vector | [0.200000,0.010742,0.000000,0.000000,0.000000,0.001526,0.000000,0.000000] |
+----+-------------------------------------------------------------------------+-------------------------------------+---------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I cannot (yet) judge whether the result is so useful.&lt;/p&gt;
&lt;h2 id="sources"&gt;Sources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/creating-the-mariadb-binary-tarball/"&gt;Creating the MariaDB Binary Tarball&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.org/wp-content/uploads/2024/02/MariaDB-Vector.pdf"&gt;MariaDB Vector&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/resources/blog/mariadb-vector-preview-is-out/"&gt;MariaDB Vector preview is out&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.org/projects/mariadb-vector/"&gt;MariaDB Vector&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://metacpan.org/pod/Perl::Tokenizer"&gt;Perl::Tokenizer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.qwak.com/post/utilizing-llms-with-embedding-stores"&gt;Integrating Vector Databases with LLMs: A Hands-On Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/qwak-ai/qwak-examples/tree/main/qa_bot_falcon_chroma"&gt;LLM Model Enhanced with Vector DB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@vipra_singh/building-llm-applications-vector-database-part-4-2bb29e7c798d"&gt;Building LLM Applications: Vector Database (Part 4)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@myscale/understanding-vector-indexing-a-comprehensive-guide-d1abe36ccd3c"&gt;Understanding Vector Indexing: A Comprehensive Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://christophergs.com/blog/understanding-llm-tokenization"&gt;The Technical User&amp;rsquo;s Introduction to LLM Tokenization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.blog/2023/10/09/from-prototype-to-production-vector-databases-in-generative-ai-applications/"&gt;From prototype to production: Vector databases in generative AI applications&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>FromDual Backup and Recovery Manager for MariaDB and MySQL 2.3.1 has been released</title><link>https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.3.1-has-been-released/</link><pubDate>Mon, 12 Aug 2024 16:25:13 +0200</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.3.1-has-been-released/</guid><description>&lt;p&gt;FromDual has the pleasure to announce the release of the new version 2.3.1 of its popular &lt;a href="https://www.fromdual.com/backup-and-recovery-manager-user-guide" title="FromDual Backup and Recovery Manager for MariaDB and MySQL"&gt;Backup and Recovery Manager for MariaDB and MySQL&lt;/a&gt; (&lt;code&gt;brman&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The new FromDual Backup and Recovery Manager can be downloaded from &lt;a href="https://support.fromdual.com/admin/public/download.php?operation=select&amp;amp;product_id=12&amp;amp;release_series_id=28&amp;amp;product_version_id=151" title="Download FromDual Backup and Recovery Manager for MariaDB and MySQL"&gt;here&lt;/a&gt;. The FromDual Repositories were updated. How to install and use the Backup and Recovery Manager is described in &lt;a href="https://www.fromdual.com/fromdual-backup-and-recovery-manager-installation-guide" title="FromDual Backup and Recovery Manager (brman) installation guide"&gt;FromDual Backup and Recovery Manager (&lt;code&gt;brman&lt;/code&gt;) installation guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the inconceivable case that you find a bug in the FromDual Backup and Recovery Manager please report it to the FromDual &lt;a href="https://support.fromdual.com/bugs/login_page.php" target="_blank" title="FromDual Bug tracker"&gt;Bugtracker&lt;/a&gt; or just send us an [email](mailto:contact@fromdual.com?Subject=Bug report for brman).&lt;/p&gt;
&lt;p&gt;Any feedback, statements and testimonials are welcome as well! Please send them to &lt;a href="mailto:feedback@fromdual.com?Subject=Feedback"&gt;feedback@fromdual.com&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="upgrade-from-2x-to-231"&gt;Upgrade from 2.x to 2.3.1&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; cd ${HOME}/product
shell&amp;gt; tar xf /download/brman-2.3.1.tar.gz
shell&amp;gt; rm -f brman
shell&amp;gt; ln -s brman-2.3.1 brman
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="changes-in-fromdual-backup-and-recovery-manager-231"&gt;Changes in FromDual Backup and Recovery Manager 2.3.1&lt;/h2&gt;
&lt;p&gt;This release is a new minor release. It contains mainly bug fixes. We have tried to maintain backward-compatibility with the 1.2, 2.0, 2.1 and 2.2 release series. But you should test the new release seriously!&lt;/p&gt;
&lt;p&gt;You can verify your current FromDual Backup Manager version with the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; fromdual_bman --version
shell&amp;gt; bman --version
shell&amp;gt; rman --version
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="general"&gt;General&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Testing: LXC library updated.&lt;/li&gt;
&lt;li&gt;Testing: Test preparation improved.&lt;/li&gt;
&lt;li&gt;General: CHANGELOG updated.&lt;/li&gt;
&lt;li&gt;General: rc made unique.&lt;/li&gt;
&lt;li&gt;Documentation: Documentation improved.&lt;/li&gt;
&lt;li&gt;Documentation: Create user documented.&lt;/li&gt;
&lt;li&gt;Documentation: New release notes added to documentation.&lt;/li&gt;
&lt;li&gt;Packaging: Distro Debian 10 removed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="fromdual-backup-manager-bman"&gt;FromDual Backup Manager (bman)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Utility mariabackup replaced by mariadb-backup.&lt;/li&gt;
&lt;li&gt;Branch guessing improved.&lt;/li&gt;
&lt;li&gt;Code refactored.&lt;/li&gt;
&lt;li&gt;No realistic password is used any more.&lt;/li&gt;
&lt;li&gt;Error message for missing client utilities made more distro specific.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="fromdual-recovery-manager-rman"&gt;FromDual Recovery Manager (rman)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Branch guessing improved.&lt;/li&gt;
&lt;li&gt;Code refactored.&lt;/li&gt;
&lt;li&gt;No realistic password is used any more.&lt;/li&gt;
&lt;li&gt;Error message for missing client utilities made more distro specific.&lt;/li&gt;
&lt;li&gt;Typo error fixed, tests refactored.&lt;/li&gt;
&lt;li&gt;In some error cases all processes were killed instead of just the dummy database daemon. This is caught correctly now.&lt;/li&gt;
&lt;li&gt;Error message improved to get more information in case of errors.&lt;/li&gt;
&lt;li&gt;Physical schema backup leads to dump which is wrong. Now this is caught and aborted with an error.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Subscriptions for commercial use of FromDual Backup and Recovery Manager you can get from [from us](mailto:contact@fromdual.com?Subject=Commercial use of FromDual brman).&lt;/p&gt;</description></item><item><title>Partial physical database restore for MariaDB and MySQL</title><link>https://www.fromdual.com/blog/partial-physical-database-restore-for-mariadb-and-mysql/</link><pubDate>Tue, 02 Jul 2024 18:13:47 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/partial-physical-database-restore-for-mariadb-and-mysql/</guid><description>&lt;h2 id="what-is-it-about"&gt;What is it about?&lt;/h2&gt;
&lt;p&gt;When describing backup and restore scenarios, a full backup and a full restore of the database instance (&lt;code&gt;mariadbd&lt;/code&gt;/&lt;code&gt;mysqld&lt;/code&gt;) are usually assumed. This means that the entire database instance, including all databases (schemas), is backed up and restored.&lt;/p&gt;
&lt;p&gt;In practice, however, the situation is often different: An entire database instance is not to be restored, but only individual databases or even individual tables, because only these have broken.&lt;/p&gt;
&lt;p&gt;In many cases, this can be done quite easily with the tools &lt;code&gt;mariadb-dump&lt;/code&gt;/&lt;code&gt;mariadb&lt;/code&gt; or &lt;code&gt;mysqldump&lt;/code&gt;/&lt;code&gt;mysql&lt;/code&gt; (logical backup). However, if the database or table is very large, the restore will not be completed in a reasonable time (some minutes to a few hours).&lt;/p&gt;
&lt;p&gt;This is exactly where the so-called partial physical restore comes into play. Partial stands for one or more tables (or an entire database), physical for: Individual SQL statements are not executed, but the data files are physically restored. In this scenario, very large amounts of data can be restored very quickly, provided the appropriate infrastructure is in place. Rule of thumb: On fat hardware: 1 Tbyte per hour. In this way, database restores can be carried out very quickly.&lt;/p&gt;
&lt;p&gt;MariaDB and MySQL already offer this functionality out of the box. The mechanism is reasonably practicable for individual tables (see &lt;a href="https://www.fromdual.com/xtrabackup_in_a_nutshell#pb_restore"&gt;Restore partial backup&lt;/a&gt;). For entire databases with possibly dozens or hundreds of tables, however, the on-board mechanism is very cumbersome and error-prone.&lt;/p&gt;
&lt;h2 id="use-case"&gt;Use case&lt;/h2&gt;
&lt;p&gt;This is exactly where the new functionality of the &lt;a href="https://www.fromdual.com/fromdual-backup-manager-2.3.0-has-been-released"&gt;FromDual Backup and Recovery Manager (brman) v2.3.0&lt;/a&gt; comes into play: it considerably simplifies the partial physical database restore.&lt;/p&gt;
&lt;p&gt;A second scenario in which this new functionality can also be used is when moving a large database from one database instance to another (e.g. from Dev to Prod).&lt;/p&gt;
&lt;h2 id="preparations-for-the-partial-physical-database-restore"&gt;Preparations for the partial physical database restore&lt;/h2&gt;
&lt;p&gt;In order to be able to restore a database, a clean backup must of course first be available. This can either be created with the FromDual Backup Manager (&lt;code&gt;bman&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PORT=3306
BACKUPNAME=bck_full_2024-07-01
BACKUPDIR=/tmp/bck

./brman/bin/bman --target=brman:secret@127.0.0.1:${PORT} --type=full --mode=physical --policy=daily --backupdir=${BACKUPDIR} --backup-name=${BACKUPNAME} --no-compress
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or you can simply create the backup with the MariaDB (&lt;code&gt;mariadb-backup&lt;/code&gt;) or MySQL on-board tools (&lt;code&gt;xtrabackup&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PORT=3306
BACKUPNAME=bck_full_2024-07-01
BACKUPDIR=/tmp/bck
POLICY=daily

mariadb-backup --user=brman --password=secret --host=127.0.0.1 --port=${PORT} --backup --target-dir=${BACKUPDIR}/${POLICY}/${BACKUPNAME}
mariadb-backup --user=brman --password=secret --host=127.0.0.1 --port=${PORT} --prepare --target-dir=${BACKUPDIR}/${POLICY}/${BACKUPNAME}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="partial-physical-database-restore"&gt;Partial physical database restore&lt;/h2&gt;
&lt;p&gt;To perform a partial physical database restore, the database must be running, in contrast to a complete physical restore.&lt;/p&gt;
&lt;p&gt;The partial physical database restore is then simple:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PORT=3306
DATADIR=/var/lib/mysql
BACKUPNAME=bck_full_2024-07-01
BACKUPDIR=/tmp/bck

./brman/bin/rman --target=brman:secret@127.0.0.1:${PORT} --type=schema --mode=physical --policy=daily --schema=test --log=/tmp/rman.log --backupdir=${BACKUPDIR} --datadir=${DATADIR} --backup-name=${BACKUPNAME}

...
Start restore at 2024-07-01 16:29:48
 Backup with tool mariabackup version 10.11.8 (from path /home/mysql/product/mariadb-10.11/bin/mariabackup).
 Parent: We are the parent. Our child is: 63712. Waiting for database daemon...
 Child: We are the child: Starting database daemon...
 Child: Change ownership of database files (/tmp/bck/daily/bck_full_2024-07-01) to mysql
 Child: /home/mysql/product/mariadb-10.11/bin/mariadbd --no-defaults --user=mysql --basedir=/home/mysql/product/mariadb-10.11 --datadir=/tmp/bck/daily/bck_full_2024-07-01 --log-error=/tmp/my.err --port=3360 --socket=/tmp/my.sock --lower-case-table-names=0
 Parent: Tables not InnoDB or sequences: 0
 Parent: Tables with partitions: 0
 Parent: Tables with full-text index: 0
 Parent: InnoDB table `test` found to restore
 Parent: Dump database test
 Parent: /home/mysql/product/mariadb-10.11/bin/mariadb-dump --user=brman --host=127.0.0.1 --port=3360 --routines --events --triggers --no-data --skip-lock-tables --add-drop-database --databases test
 Parent: Shutdown backup database.
 Restore empty database test
 Prepare and export tables: /home/mysql/product/mariadb-10.11/bin/mariabackup --user=brman --host=127.0.0.1 --port=3321 --prepare --export --databases=test --target-dir=/tmp/bck/daily/bck_full_2024-07-01
 SET SESSION foreign_key_checks = 0
 SET SESSION sql_log_bin = off

 Restore table test
 ALTER TABLE `test`.`test` DISCARD TABLESPACE
 cp /tmp/bck/daily/bck_full_2024-07-01/test/test.cfg /home/mysql/database/mariadb-1011/data/test/test.cfg
 cp /tmp/bck/daily/bck_full_2024-07-01/test/test.ibd /home/mysql/database/mariadb-1011/data/test/test.ibd
 chown mysql: /home/mysql/database/mariadb-1011/data/test/test.cfg /home/mysql/database/mariadb-1011/data/test/test.ibd
 ALTER TABLE `test`.`test` IMPORT TABLESPACE
 rm /home/mysql/database/mariadb-1011/data/test/test.cfg
 rm /tmp/bck/daily/bck_full_2024-07-01/test/test.cfg
 ----------------------------------------
 WARNING: You should restart the database now! Otherwise possible future backups may fail. See MDEV-34418 (https://jira.mariadb.org/browse/MDEV-34418).
 ----------------------------------------

 Restore time was: 0d 0h 0' 2&amp;quot;
End restore at 2024-07-01 16:29:50 (rc=0)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For MariaDB, it is recommended to restart the database afterwards until the bug MDEV-34418: &lt;a href="https://jira.mariadb.org/browse/MDEV-34418" target="_blank"&gt;mariadb-backup fails on database which was partially restored with mariadb-backup&lt;/a&gt; is fixed. This step can be omitted for MySQL.&lt;/p&gt;
&lt;h2 id="restrictions"&gt;Restrictions&lt;/h2&gt;
&lt;p&gt;At present, the following restrictions still apply to the partial physical restore of databases with &lt;code&gt;rman&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Only entire databases can be restored. Restoring individual tables is not yet implemented. Use the basic on-board tools for this.&lt;/li&gt;
&lt;li&gt;Restoring partitioned tables is not yet implemented. Use the basic on-board tools for partitioned tables.&lt;/li&gt;
&lt;li&gt;A subsequent point-in-time recovery of the database is not yet implemented and must be carried out manually.&lt;/li&gt;
&lt;li&gt;A partial physical database restore for an entire Galera cluster is not yet implemented and must be performed manually. In this case, a restore to one Galera node and a subsequent synchronisation of the other nodes using SST is recommended.&lt;/li&gt;
&lt;li&gt;With a physical partial database restore, a pseudo instance is started on the backup files. This pseudo instance requires a free port 3360.&lt;/li&gt;
&lt;li&gt;The backup files must already be in a consistent state (&lt;code&gt;--prepare&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;With a partial physical database restore, a logical backup of the database is created without the data on the pseudo instance. This backup is restored to the instance to be repaired. This means that all objects (views, triggers, functions, procedures, events, etc.) that were created AFTER the complete physical backup are deleted before the partial physical database restore and are then no longer available.&lt;/li&gt;
&lt;li&gt;The original database instance from which the backup was created and the instance on which the restore is performed must have the same setting for &lt;code&gt;lower_case_table_names&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;All three, the backup, the database instance and the &lt;code&gt;rman&lt;/code&gt; tool must be located on the same machine.&lt;/li&gt;
&lt;li&gt;The backup must currently still be available in uncompressed form.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="literature"&gt;Literature&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/xtrabackup_in_a_nutshell#partial"&gt;Partial Backup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/partial-backup-and-restore-with-mariabackup/" target="_blank"&gt;Partial Backup and Restore with Mariabackup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/innodb-file-per-table-tablespaces/#importing-transportable-tablespaces-for-non-partitioned-tables" target="_blank"&gt;Copying Transportable Tablespaces for Non-partitioned Tables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/mysql-enterprise-backup/8.4/en/backup-partial-options.html" target="_blank"&gt;Partial Backup and Restore Options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.percona.com/percona-xtrabackup/2.4/innobackupex/partial_backups_innobackupex.html#restoring-partial-backups" target="_blank"&gt;Partial Backups&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>FromDual Backup and Recovery Manager for MariaDB and MySQL 2.3.0 has been released</title><link>https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.3.0-has-been-released/</link><pubDate>Tue, 25 Jun 2024 15:12:02 +0200</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/brman-release-notes/fromdual-backup-manager-2.3.0-has-been-released/</guid><description>&lt;p&gt;FromDual has the pleasure to announce the release of the new version 2.3.0 of its popular &lt;a href="https://www.fromdual.com/backup-and-recovery-manager-user-guide" title="FromDual Backup and Recovery Manager for MariaDB and MySQL"&gt;Backup and Recovery Manager for MariaDB and MySQL&lt;/a&gt; (&lt;code&gt;brman&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The new FromDual Backup and Recovery Manager can be downloaded from &lt;a href="https://support.fromdual.com/admin/public/download.php?operation=select&amp;amp;product_id=12&amp;amp;release_series_id=28&amp;amp;product_version_id=151" title="Download FromDual Backup and Recovery Manager for MariaDB and MySQL"&gt;here&lt;/a&gt;. The FromDual Repositories were updated. How to install and use the Backup and Recovery Manager is described in &lt;a href="https://www.fromdual.com/fromdual-backup-and-recovery-manager-installation-guide" title="FromDual Backup and Recovery Manager (brman) installation guide"&gt;FromDual Backup and Recovery Manager (&lt;code&gt;brman&lt;/code&gt;) installation guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the inconceivable case that you find a bug in the FromDual Backup and Recovery Manager please report it to the FromDual &lt;a href="https://support.fromdual.com/bugs/login_page.php" target="_blank" title="FromDual Bug tracker"&gt;Bugtracker&lt;/a&gt; or just send us an [email](mailto:contact@fromdual.com?Subject=Bug report for brman).&lt;/p&gt;
&lt;p&gt;Any feedback, statements and testimonials are welcome as well! Please send them to &lt;a href="mailto:feedback@fromdual.com?Subject=Feedback"&gt;feedback@fromdual.com&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="upgrade-from-2x-to-230"&gt;Upgrade from 2.x to 2.3.0&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; cd ${HOME}/product
shell&amp;gt; tar xf /download/brman-2.3.0.tar.gz
shell&amp;gt; rm -f brman
shell&amp;gt; ln -s brman-2.3.0 brman
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="changes-in-fromdual-backup-and-recovery-manager-230"&gt;Changes in FromDual Backup and Recovery Manager 2.3.0&lt;/h2&gt;
&lt;p&gt;This release is a new major release. The most important new feature is the &lt;strong&gt;partial physical restore&lt;/strong&gt;. We have tried to maintain backward-compatibility with the 1.2, 2.0, 2.1 and 2.2 release series. But you should test the new release seriously!&lt;/p&gt;
&lt;p&gt;You can verify your current FromDual Backup Manager version with the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; fromdual_bman --version
shell&amp;gt; bman --version
shell&amp;gt; rman --version
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="general"&gt;General&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Packaging: Release el9 added and debian format increase from 9 to 10 because of debian12.&lt;/li&gt;
&lt;li&gt;Documentation prepared for Asciidoctor.&lt;/li&gt;
&lt;li&gt;Distribtion dependent things fixed.&lt;/li&gt;
&lt;li&gt;Build script improved.&lt;/li&gt;
&lt;li&gt;Typos fixed.&lt;/li&gt;
&lt;li&gt;All print replaced by standard PHP echo commands.&lt;/li&gt;
&lt;li&gt;Redhat replace by Red Hat and CentOS by Rocky Linux.&lt;/li&gt;
&lt;li&gt;Copyright year updated to 2024.&lt;/li&gt;
&lt;li&gt;Library myEnv updated (&lt;code&gt;getDistribution&lt;/code&gt;, &lt;code&gt;lsb_release&lt;/code&gt; removed).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="fromdual-backup-manager-bman"&gt;FromDual Backup Manager (bman)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Bug in &lt;code&gt;sftp&lt;/code&gt; transfer for archiving files fixed.&lt;/li&gt;
&lt;li&gt;Also create subdirectories only once if necessary in physical backup.&lt;/li&gt;
&lt;li&gt;Archive location directory is only created once in physical backup. This avoids errors and makes the backup slightly faster.&lt;/li&gt;
&lt;li&gt;In function &lt;code&gt;createArchiveDestinationDirectory&lt;/code&gt; &lt;code&gt;php-ssh2&lt;/code&gt; calls where replaced by the more stable &lt;code&gt;scp&lt;/code&gt;/&lt;code&gt;sftp&lt;/code&gt; calls.&lt;/li&gt;
&lt;li&gt;Bug in archive destination directory creation fixed and example improved.&lt;/li&gt;
&lt;li&gt;Library LXClib added for testing.&lt;/li&gt;
&lt;li&gt;Number of lines in dump parsing increased because of changes in MySQL 8.0.&lt;/li&gt;
&lt;li&gt;Binlog backup debug output made nicer.&lt;/li&gt;
&lt;li&gt;Retention time increased from 800 days to 1200 days (more than 3 years), tests added for this, newer DB versions added to tests.&lt;/li&gt;
&lt;li&gt;Advices &lt;code&gt;apt-get&lt;/code&gt; and &lt;code&gt;yum&lt;/code&gt; replace by &lt;code&gt;apt&lt;/code&gt; and &lt;code&gt;dnf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Error was not returned correctly when &lt;code&gt;bman&lt;/code&gt; aborts because of MyISAM tables. Fixed.&lt;/li&gt;
&lt;li&gt;Syntax error fixed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flock&lt;/code&gt; on &lt;code&gt;fpmmm&lt;/code&gt; file added.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BINLOG MONITOR&lt;/code&gt; privilege check added for MariaDB 10.11.&lt;/li&gt;
&lt;li&gt;Code clean-up.&lt;/li&gt;
&lt;li&gt;Example enhanced.&lt;/li&gt;
&lt;li&gt;Output made more clear for trouble shooting (&lt;code&gt;doCleanup&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="fromdual-recovery-manager-rman"&gt;FromDual Recovery Manager (rman)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Various bugs fixed found during automated testing.&lt;/li&gt;
&lt;li&gt;Some minor fixes about timing and repeatable testing, warnings and messages improved.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mariadb_backup_binlog_info&lt;/code&gt; case (MariaDB 11.4) added for physical full backup.&lt;/li&gt;
&lt;li&gt;Code refactored and case when backup is compressed caught.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;doPhysicalRestore&lt;/code&gt; renamed to &lt;code&gt;doFullPhysicalRestore&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Split restore functions in their own files.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sql_log_bin&lt;/code&gt; is used for schema restore on partial physical restore.&lt;/li&gt;
&lt;li&gt;New example for partial physical restore added.&lt;/li&gt;
&lt;li&gt;New method for partial physical restore implemented.&lt;/li&gt;
&lt;li&gt;Partial physical schema restore added.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Subscriptions for commercial use of FromDual Backup and Recovery Manager you can get from [from us](mailto:contact@fromdual.com?Subject=Commercial use of FromDual brman).&lt;/p&gt;</description></item><item><title>Shrinking the InnoDB system tablespace</title><link>https://www.fromdual.com/blog/shrinking-the-innodb-system-tablespace/</link><pubDate>Mon, 17 Jun 2024 14:45:32 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/shrinking-the-innodb-system-tablespace/</guid><description>&lt;p&gt;One feature that really excited me in the new MariaDB 11.4 LTS release is the shrinking of the system tablespace (&lt;code&gt;ibdata1&lt;/code&gt;). I have been eagerly waiting for this feature since around 2006 and now it has finally arrived with MariaDB 11.4.
Actually, this feature has been available since &lt;a href="https://www.fromdual.com/enterprise-support-for-mariadb-and-mysql#mariadb-eol"&gt;MariaDB 11.2 IR&lt;/a&gt; (June 2023).&lt;/p&gt;
&lt;p&gt;Unfortunately, the announcement of this feature came a little too short. In the MariaDB release notes it says succinctly:&lt;/p&gt;
&lt;figure&gt;
&lt;blockquote&gt;
&lt;p&gt;The InnoDB system tablespace is now shrunk by reclaiming unused space at startup (&lt;a href="https://jira.mariadb.org/browse/MDEV-14795" target="_blank"&gt;MDEV-14795&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figcaption&gt;From the &lt;a href="https://mariadb.com/kb/en/mariadb-11-2-0-release-notes/"&gt;MariaDB 11.2.0 Release Notes&lt;/a&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The reasons why this file can grow immeasurably have actually been known for a long time and the measures against it are also clear (see &lt;a href="https://www.fromdual.com/blog/shrinking-the-innodb-system-tablespace/#literature"&gt;literature&lt;/a&gt;). But again and again we see MariaDB users out in the field who didn&amp;rsquo;t realise the problem or realised it too late and are now left with an &lt;code&gt;ibdata1&lt;/code&gt; file that is far too large&amp;hellip;&lt;/p&gt;
&lt;h2 id="how-can-the-problem-be-provoked"&gt;How can the problem be provoked?&lt;/h2&gt;
&lt;p&gt;The problem can be provoked by creating a table in the system tablespace:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SET global innodb_file_per_table = off;

SQL&amp;gt; CREATE TABLE `test` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `data` varchar(128) DEFAULT NULL,
 `ts` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
 PRIMARY KEY (`id`)
) ENGINE=InnoDB;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then filling it with data:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; INSERT INTO test
SELECT NULL, 'Some data to provoke huge data growth in system tablespace', NOW()
;

SQL&amp;gt; INSERT INTO test
SELECT NULL, 'Some data to provoke huge data growth in system tablespace', NOW()
 FROM test LIMIT 1000000
;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While the table is being filled, you can observe how the file &lt;code&gt;ibdata1&lt;/code&gt; swells on the file system:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ while [ 1 ] ; do ll -h ibdata1 ; sleep 5 ; done
-rw-rw---- 1 mysql mysql 12M Jun 2 13:57 ibdata1
-rw-rw---- 1 mysql mysql 76M Jun 12 13:57 ibdata1
-rw-rw---- 1 mysql mysql 76M Jun 12 13:57 ibdata1
-rw-rw---- 1 mysql mysql 140M Jun 12 13:58 ibdata1
-rw-rw---- 1 mysql mysql 204M Jun 12 13:58 ibdata1
-rw-rw---- 1 mysql mysql 268M Jun 12 13:58 ibdata1
-rw-rw---- 1 mysql mysql 332M Jun 12 13:59 ibdata1
-rw-rw---- 1 mysql mysql 396M Jun 12 13:59 ibdata1
-rw-rw---- 1 mysql mysql 460M Jun 12 13:59 ibdata1
-rw-rw---- 1 mysql mysql 524M Jun 12 13:59 ibdata1
-rw-rw---- 1 mysql mysql 588M Jun 12 13:59 ibdata1
-rw-rw---- 1 mysql mysql 652M Jun 12 13:59 ibdata1
-rw-rw---- 1 mysql mysql 716M Jun 12 13:59 ibdata1
-rw-rw---- 1 mysql mysql 780M Jun 12 14:00 ibdata1
-rw-rw---- 1 mysql mysql 844M Jun 12 14:00 ibdata1
-rw-rw---- 1 mysql mysql 908M Jun 12 14:00 ibdata1
-rw-rw---- 1 mysql mysql 972M Jun 12 14:00 ibdata1
-rw-rw---- 1 mysql mysql 1.1G Jun 12 14:00 ibdata1
-rw-rw---- 1 mysql mysql 1.2G Jun 12 14:00 ibdata1
-rw-rw---- 1 mysql mysql 1.3G Jun 12 14:00 ibdata1
-rw-rw---- 1 mysql mysql 1.4G Jun 12 14:00 ibdata1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the &lt;code&gt;ibdata1&lt;/code&gt; file is large enough, you can move the table from the system tablespace to a dedicated tablespace:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SET global innodb_file_per_table = off;
SQL&amp;gt; ALTER TABLE test.test FORCE;
Query OK, 0 rows affected (33.764 sec)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you can see how the new file is created:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ll -h ibdata1 test/*
-rw-rw---- 1 mysql mysql 1.4G Jun 12 14:01 ibdata1
-rw-rw---- 1 mysql mysql 1.1K Jun 12 14:01 test/#sql-alter-dca30-12.frm
-rw-rw---- 1 mysql mysql 696M Jun 12 14:01 test/#sql-alter-dca30-12.ibd
-rw-rw---- 1 mysql mysql 1.1K Jun 12 13:56 test/test.frm

-rw-rw---- 1 mysql mysql 1.4G Jun 12 14:01 ibdata1
-rw-rw---- 1 mysql mysql 1.1K Jun 12 14:01 test/test.frm
-rw-rw---- 1 mysql mysql 1.4G Jun 12 14:02 test/test.ibd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So now we have once the data but twice as much space used.&lt;/p&gt;
&lt;h2 id="and-how-can-you-make-the-system-tablespace-smaller-again"&gt;And how can you make the system tablespace smaller again?&lt;/h2&gt;
&lt;p&gt;Unfortunately, this information is somewhat hidden and has to be gathered from the documentation and the MariaDB Jira issues (see &lt;a href="https://www.fromdual.com/blog/shrinking-the-innodb-system-tablespace/#literature"&gt;literature&lt;/a&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SET GLOBAL innodb_fast_shutdown=0;
SQL&amp;gt; SHUTDOWN;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When shutting down, you can see the corresponding entries in the MariaDB error log:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Note] bin/mariadbd (initiated by: root[root] @ localhost []): Normal shutdown
[Note] InnoDB: FTS optimize thread exiting.
[Note] InnoDB: Truncating system tablespace from 90880 to 768 pages
[Note] InnoDB: System tablespace truncated successfully
[Note] InnoDB: Starting shutdown...
[Note] InnoDB: Dumping buffer pool(s) to /home/mysql/database/mariadb-114/data/ib_buffer_pool
[Note] InnoDB: Restricted to 2016 pages due to innodb_buf_pool_dump_pct=25
[Note] InnoDB: Buffer pool(s) dump completed at 240612 14:11:11
[Note] InnoDB: Removed temporary tablespace data file: &amp;quot;./ibtmp1&amp;quot;
[Note] InnoDB: Shutdown completed; log sequence number 4011132308; transaction id 139
[Note] bin/mariadbd: Shutdown complete
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And if you look at the file &lt;code&gt;ibdata1&lt;/code&gt; on disc afterwards, it is as small as it was at the beginning of the experiment:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ll ibdata1* -h
-rw-rw---- 1 mysql mysql 12M Jun 12 14:11 ibdata1
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="literature"&gt;Literature&lt;/h2&gt;
&lt;p&gt;See also:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/undo-logs-in-innodb-system-tablespace-ibdata1"&gt;UNDO logs in InnoDB system tablespace ibdata1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/shrinking-innodb-system-tablespace-file-ibdata1-poc"&gt;Shrinking InnoDB system tablespace file ibdata1 PoC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/who-else-is-using-my-memory-file-system-cache-analysis"&gt;Who else is using my memory - File System Cache analysis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;InnoDB system tablespace cannot be shrunk (&lt;a href="https://jira.mariadb.org/browse/MDEV-14795" target="_blank"&gt;MDEV-14795&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;ibdata1 shrinking (&lt;a href="https://jira.mariadb.org/browse/MDEV-31462" target="_blank"&gt;MDEV-31462&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;InnoDB System Tablespaces - &lt;a href="https://mariadb.com/kb/en/innodb-system-tablespaces/#decreasing-the-size" target="_blank"&gt;Decreasing the Size&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>MDEV-34412</title><link>https://www.fromdual.com/blog/migrating-from-mysql-master-master-to-galera-replication/comment-1064/</link><pubDate>Mon, 17 Jun 2024 12:05:44 +0200</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/migrating-from-mysql-master-master-to-galera-replication/comment-1064/</guid><description>&lt;p&gt;&lt;a href="https://jira.mariadb.org/browse/MDEV-34412"&gt;https://jira.mariadb.org/browse/MDEV-34412&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Migration Problem mysql 5.7 to mariadb/galera</title><link>https://www.fromdual.com/blog/migrating-from-mysql-master-master-to-galera-replication/comment-1063/</link><pubDate>Mon, 17 Jun 2024 11:53:57 +0200</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/migrating-from-mysql-master-master-to-galera-replication/comment-1063/</guid><description>&lt;p&gt;Hi dcz01&lt;/p&gt;
&lt;p&gt;No it is not solved&amp;hellip; It is closed and &amp;ldquo;not a bug&amp;rdquo;&amp;hellip; I try to intervene&lt;/p&gt;
&lt;p&gt;Regards,
Oli&lt;/p&gt;</description></item><item><title>Migration Problem mysql 5.7 to mariadb/galera</title><link>https://www.fromdual.com/blog/migrating-from-mysql-master-master-to-galera-replication/comment-1062/</link><pubDate>Mon, 17 Jun 2024 11:39:19 +0200</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/migrating-from-mysql-master-master-to-galera-replication/comment-1062/</guid><description>&lt;p&gt;Hi Oli,
Thanks for your answer.
The problem is already open and solved but not for me and its still not working:
&lt;a href="https://jira.mariadb.org/browse/MDEV-28172"&gt;https://jira.mariadb.org/browse/MDEV-28172&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Greetings
dcz01&lt;/p&gt;</description></item><item><title>Possibly a bug</title><link>https://www.fromdual.com/blog/migrating-from-mysql-master-master-to-galera-replication/comment-1061/</link><pubDate>Mon, 17 Jun 2024 11:29:33 +0200</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/migrating-from-mysql-master-master-to-galera-replication/comment-1061/</guid><description>&lt;p&gt;Hello dcz01&lt;/p&gt;
&lt;p&gt;I would say, this is probably a bug. I can reproduce it on my system (MySQL 5.7 Master and MariaDB 10.6 Galera Cluster).&lt;/p&gt;
&lt;p&gt;Please contact your MariaDB support contact&amp;hellip; If you need assistance we are happy to sell you our remote-DBA services&amp;hellip;&lt;/p&gt;
&lt;p&gt;Regards,
Oli&lt;/p&gt;</description></item><item><title>Migration from mysql 5.7 to MariaDB 10.5 with Galera 4 Problems</title><link>https://www.fromdual.com/blog/migrating-from-mysql-master-master-to-galera-replication/comment-1060/</link><pubDate>Mon, 17 Jun 2024 08:56:15 +0200</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/migrating-from-mysql-master-master-to-galera-replication/comment-1060/</guid><description>&lt;p&gt;Hi,
we are migrating some old mysql 5.7 servers to new mariadb 10.5 machines with new galera 4 and we&amp;rsquo;re doing the normal way of migration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dumping all databases from old servers and importing to new galera cluster (no error)&lt;/li&gt;
&lt;li&gt;Configuration of traditional sql replication between old and new servers so that clients still can connect to servers without downtime (no errors)&lt;/li&gt;
&lt;li&gt;Starting replication and just creating a new database (error and galera nodes which are not the replication slave are dropping with inconsistency from cluster)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Do you know what could be the failure here?
You described it here very good but its not working so easy.&lt;/p&gt;
&lt;p&gt;Greetings
dcz01&lt;/p&gt;</description></item><item><title>How to downgrade MariaDB or MySQL</title><link>https://www.fromdual.com/blog/downgrade-mariadb-or-mysql/</link><pubDate>Tue, 21 May 2024 09:54:14 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/downgrade-mariadb-or-mysql/</guid><description>&lt;p&gt;On this page we have summarised information about downgrading a MariaDB/MySQL database. We do not cover migrating from MySQL to MariaDB or vice versa. For migrations (sidegrade) please look here: &lt;a href="https://www.fromdual.com/mysql-mariadb-migration"&gt;MySQL - MariaDB migration&lt;/a&gt; and here: &lt;a href="https://www.fromdual.com/migration-between-mysql-percona-server-and-mariadb"&gt;Migration between MySQL/Percona Server and MariaDB&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The downgrade process tends to be neglected because nobody really wants to do it. So we are in swampy territory here. Unforeseen situations can occur very easily and good preparation is essential.&lt;/p&gt;
&lt;p&gt;I can think of the following possible options for the downgrade:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Restore the backup that was made BEFORE the upgrade began.&lt;/li&gt;
&lt;li&gt;Binary inplace downgrade (which is NOT supported in many cases).&lt;/li&gt;
&lt;li&gt;Dump (&lt;code&gt;mariadb-dump&lt;/code&gt;/&lt;code&gt;mysqldump&lt;/code&gt;) of the upgraded database and restore (&lt;code&gt;mariadb&lt;/code&gt;/&lt;code&gt;mysql&lt;/code&gt;) to the old version (logical backup/restore).&lt;/li&gt;
&lt;li&gt;Master/slave replication (with Statement Based Replication (SBR) or Row Based Replication (RBR)) and fallback to the slave with the old version.&lt;/li&gt;
&lt;li&gt;Partial Backup/Restore with &lt;code&gt;mariadb-backup&lt;/code&gt;/&lt;code&gt;xtrabackup&lt;/code&gt; (Transportable Tablespace (TTS) method).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All these options have their advantages and disadvantages and must be carefully tested in advance.&lt;/p&gt;
&lt;h2 id="downgrade-mariadb"&gt;Downgrade MariaDB&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/downgrade-mariadb/" target="_blank"&gt;Downgrade MariaDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/downgrading-between-major-versions-of-mariadb/" target="_blank"&gt;Downgrading between Major Versions of MariaDB&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;blockquote&gt;
&lt;p&gt;Downgrading MariaDB is not officially supported between major versions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figcaption&gt;First sentence in &lt;a href="https://mariadb.com/kb/en/downgrading-between-major-versions-of-mariadb/"&gt;&lt;/a&gt;Downgrading between Major Versions of MariaDB by MariaDB Foundation.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;FromDual says: But it usually works. Downgrading from minor versions practically always works.&lt;/p&gt;
&lt;h3 id="physical-in-place-downgrade-not-possible"&gt;Physical (in-place) downgrade NOT possible:&lt;/h3&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;From version&lt;/th&gt;
 &lt;th&gt;To version&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;11.0 or later&lt;/td&gt;
 &lt;td&gt;to 10.4 or earlier: NOT possible&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;11.0 or later&lt;/td&gt;
 &lt;td&gt;to 10.5 or later: Possible with restrictions&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;10.8 or later&lt;/td&gt;
 &lt;td&gt;unclear description&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;10.5&lt;/td&gt;
 &lt;td&gt;to 10.4: With restrictions&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;10.5&lt;/td&gt;
 &lt;td&gt;to 10.3: With restrictions or problems&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;10.3&lt;/td&gt;
 &lt;td&gt;to 10.2: With restrictions&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In addition:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Andrew Hutchings, MariaDB Foundation, 17. Mai 2024: &lt;a href="https://mariadb.org/mariadb-dump-file-compatibility-change/" target="_blank"&gt;MariaDB Dump File Compatibility Change&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="downgrade-mysql"&gt;Downgrade MySQL&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.4/en/downgrading.html" target="_blank"&gt;Downgrading MySQL (8.4)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/downgrading.html" target="_blank"&gt;Downgrading MySQL (8.0)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;blockquote&gt;
&lt;p&gt;Downgrade from MySQL 8.0 to MySQL 5.7, or from a MySQL 8.0 release to a previous MySQL 8.0 release, is not supported. The only supported alternative is to restore a backup taken before upgrading. It is therefore imperative that you back up your data before starting the upgrade process.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figcaption&gt;First and only sentence in &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/downgrading.html"&gt;Downgrading MySQL&lt;/a&gt; (8.0) by Oracle Corp.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/refman/5.7/en/downgrading.html" target="_blank"&gt;Downgrading MySQL (5.7)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.4/en/replication-upgrade.html" target="_blank"&gt;Upgrading or Downgrading a Replication Topology (8.4)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>FromDual Ops Center 1.2.2 for MariaDB and MySQL databases has been released</title><link>https://www.fromdual.com/blog/ops-center-release-notes/fromdual-ops-center-1.2.2-for-mariadb-mysql-and-compatible-databases-has-been-released/</link><pubDate>Mon, 29 Apr 2024 17:41:04 +0200</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/ops-center-release-notes/fromdual-ops-center-1.2.2-for-mariadb-mysql-and-compatible-databases-has-been-released/</guid><description>&lt;p&gt;FromDual is pleased to announce the release of the new version 1.2.2 of the popular FromDual Ops Center &lt;a href="https://www.fromdual.com/ops-center-general-information"&gt;focmm&lt;/a&gt;, a Graphical User Interface (GUI) for MariaDB, MySQL and compatible databases.&lt;/p&gt;
&lt;p&gt;The FromDual Ops Center for MariaDB and MySQL (focmm) helps DBAs and system administrators to better manage their MariaDB and MySQL databases and Galera Cluster farms. Ops Center makes life easier for DBAs and Admins!&lt;/p&gt;
&lt;p&gt;The main purpose of the Ops Center is to help you with your daily MariaDB and MySQL operations. More information about FromDual Ops Center can be found in the &lt;a href="https://www.fromdual.com/ops-center-general-information" title="General Information"&gt;General Information&lt;/a&gt; section.&lt;/p&gt;
&lt;h2 id="download-now"&gt;Download now&lt;/h2&gt;
&lt;p&gt;The new FromDual Ops Center for MariaDB and MySQL (&lt;code&gt;focmm&lt;/code&gt;) can be downloaded from our &lt;a href="https://support.fromdual.com/admin/public/download.php?product_id=11" target="_blank" title="FromDual download"&gt;download page&lt;/a&gt;. How to install and use &lt;code&gt;focmm&lt;/code&gt; is documented in the &lt;a href="https://www.fromdual.com/ops-center-user-guide" title="Ops Center User Guide"&gt;Ops Center User Guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the unlikely event that you find a bug in the FromDual Ops Center for MariaDB and MySQL please report it to the FromDual &lt;a href="https://support.fromdual.com/bugs/login_page.php" target="_blank" title="FromDual bug tracker"&gt;bug tracker&lt;/a&gt; or just send us an [email](mailto:contact@fromdual.com?Subject=Bug report for focmm).&lt;/p&gt;
&lt;p&gt;Any feedback, comments and testimonials are also welcome! Please send them to [feedback@fromdual.com](mailto:feedback@fromdual.com?Subject=Feedback for focmm &amp;ldquo;Feedback for focmm&amp;rdquo;).&lt;/p&gt;
&lt;h2 id="installing-ops-center-122"&gt;Installing Ops Center 1.2.2&lt;/h2&gt;
&lt;p&gt;Information on how to install FromDual Ops Center can be found in the &lt;a href="https://www.fromdual.com/ops-center-installing-and-upgrading" title="Installing and Upgrading"&gt;Ops Center User Guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="upgrading-from-09x-to-122"&gt;Upgrading from 0.9.x to 1.2.2&lt;/h2&gt;
&lt;p&gt;The upgrade from 0.9.x to 1.2.2 should be automatic. Please &lt;a href="https://www.fromdual.com/ops-center-upgrading"&gt;make a backup&lt;/a&gt; of your Ops Center database instance before upgrading! See also &lt;a href="https://www.fromdual.com/ops-center-upgrading"&gt;Upgrading&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; In some cases the directory &lt;code&gt;focmm/tmp/start_jobs.lock&lt;/code&gt; is missing. In this case jobs will not start. Please check the log file under &lt;code&gt;focmm/log/start_jobs.log&lt;/code&gt; and create the folder accordingly. There should also be a file called &lt;code&gt;pid&lt;/code&gt; in this folder. Create this file if it does not exist.&lt;/p&gt;
&lt;h2 id="downgrading-from-122"&gt;Downgrading from 1.2.2&lt;/h2&gt;
&lt;p&gt;Downgrading from 1.2.2 to 1.2.1 should work.&lt;/p&gt;
&lt;h2 id="changes-in-ops-center-122"&gt;Changes in Ops Center 1.2.2&lt;/h2&gt;
&lt;h3 id="machine"&gt;Machine&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Machine information is automatically gathered after first successful check now.&lt;/li&gt;
&lt;li&gt;Machine function calls optimized.&lt;/li&gt;
&lt;li&gt;Ssh key check added for machine.&lt;/li&gt;
&lt;li&gt;Some tests around machine library added.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;createPublicKey&lt;/code&gt; + page refactored.&lt;/li&gt;
&lt;li&gt;Copy of ssh key and ssh command implemented.&lt;/li&gt;
&lt;li&gt;Skip machines which are down during gathering resource costs.&lt;/li&gt;
&lt;li&gt;Error message in pricing when adding a new machine was fixed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="instance"&gt;Instance&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Instance operations are now faster when instance is running but not reachable.&lt;/li&gt;
&lt;li&gt;Node check improved in cluster and instance, works now also correctly on multi instance environments.&lt;/li&gt;
&lt;li&gt;PID file is gathered now.&lt;/li&gt;
&lt;li&gt;Stop instance on instance operations improved if a Galera cluster node.&lt;/li&gt;
&lt;li&gt;Instance is now checked immediately after start or restart and checks are set to failed after instance stop. So the instance state is more appropriate and in time now.&lt;/li&gt;
&lt;li&gt;Link added to &lt;code&gt;read_only&lt;/code&gt; variable comment.&lt;/li&gt;
&lt;li&gt;Instance is shown orange when ping check was not run yet. This is fixed now.&lt;/li&gt;
&lt;li&gt;Error log gathering improved in instance operations.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;mysql_upgrade_info&lt;/code&gt; file is missing error is suppressed now.&lt;/li&gt;
&lt;li&gt;Gather instance information is done now right after the first successful check.&lt;/li&gt;
&lt;li&gt;Check &lt;code&gt;database_ping&lt;/code&gt; was removed from general instance tests to avoid noise in the database error log.&lt;/li&gt;
&lt;li&gt;Check &lt;code&gt;instance_ping_check&lt;/code&gt; removed from &lt;code&gt;instanceTest&lt;/code&gt; to avoid error log messages on a regular base, wondering what kind of impact this has&amp;hellip;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;innodb_log_writer_threads&lt;/code&gt; rule added to instance configuration.&lt;/li&gt;
&lt;li&gt;Target connect function error logging improved.&lt;/li&gt;
&lt;li&gt;Continue button is handled correctly now when stopping, starting or restarting an instance.&lt;/li&gt;
&lt;li&gt;Instance operations location of error log is shown now.&lt;/li&gt;
&lt;li&gt;Refactored instance operations code for moving Galera buttons out.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;refreshInstance&lt;/code&gt; refactored because we need this information for Galera Cluster.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Unknown array_keys&lt;/code&gt; error message fixed in instance.&lt;/li&gt;
&lt;li&gt;Foreign MariaDB/MySQL repositories should now be considered as well.&lt;/li&gt;
&lt;li&gt;Optimized instance handling.&lt;/li&gt;
&lt;li&gt;Instance error log handling can now handle &lt;code&gt;systemd/journalctl&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Instance hardening when creating instance improved.&lt;/li&gt;
&lt;li&gt;Create instance improved.&lt;/li&gt;
&lt;li&gt;Create instance bug fixed.&lt;/li&gt;
&lt;li&gt;Instance create on Rocky 9, fixed.&lt;/li&gt;
&lt;li&gt;Create instance for Rocky 8 improved.&lt;/li&gt;
&lt;li&gt;Check for restart also removed, so also restart works now.&lt;/li&gt;
&lt;li&gt;Check removed to allow a running but not reachable instance to be restarted, restart and start button added.&lt;/li&gt;
&lt;li&gt;Non existing configuration was not handled correctly, fixed.&lt;/li&gt;
&lt;li&gt;Edit instance placeholder added and default instance name changed from &lt;code&gt;mysqld&lt;/code&gt; to &lt;code&gt;mariadbd&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create instance output made nicer in case of failure.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cluster"&gt;Cluster&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Cluster overview signal lights are also working now for Galera.&lt;/li&gt;
&lt;li&gt;Cluster operations returns faster now if machine is not reachable.&lt;/li&gt;
&lt;li&gt;Cluster show checks non important information removed.&lt;/li&gt;
&lt;li&gt;Cluster checks in menu are now shown correctly.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;grastate.dat&lt;/code&gt; async check added.&lt;/li&gt;
&lt;li&gt;Cluster check made async.&lt;/li&gt;
&lt;li&gt;Instance state added to cluster operations and check view.&lt;/li&gt;
&lt;li&gt;M/S cluster tests made more robust against strange situations.&lt;/li&gt;
&lt;li&gt;Some bugs in M/S cluster fixed.&lt;/li&gt;
&lt;li&gt;focmm user passwords should sync in galera.&lt;/li&gt;
&lt;li&gt;Bootstrap should distribute focmm user on all nodes.&lt;/li&gt;
&lt;li&gt;Bootstrap on Debian fixed again.&lt;/li&gt;
&lt;li&gt;Error message for missing &lt;code&gt;grastate.dat&lt;/code&gt; file is suppressed now.&lt;/li&gt;
&lt;li&gt;Deploy configuration button is now on a new line.&lt;/li&gt;
&lt;li&gt;2 little bugs in M/S cluster operations removed.&lt;/li&gt;
&lt;li&gt;Instance operations improved with Galera clusters.&lt;/li&gt;
&lt;li&gt;Soft bootstrap implemented.&lt;/li&gt;
&lt;li&gt;Cluster node bootstrap, start stop fixed.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;bootstrap&lt;/code&gt; implemented.&lt;/li&gt;
&lt;li&gt;Async rolling cluster restart added.&lt;/li&gt;
&lt;li&gt;Problem with rolling restart fixed.&lt;/li&gt;
&lt;li&gt;Cluster check and operations is read if not OK. Failed, same behaviour as before!&lt;/li&gt;
&lt;li&gt;Rolling cluster restart and other buttons added to cluster operations.&lt;/li&gt;
&lt;li&gt;Variable &lt;code&gt;wsrep_node_name&lt;/code&gt; is set to instance name per default.&lt;/li&gt;
&lt;li&gt;Galera cluster config deployment made smoother and fixed bug.&lt;/li&gt;
&lt;li&gt;Sort order of cluster nodes and title of table clarified.&lt;/li&gt;
&lt;li&gt;Page start/stop notices added to &lt;code&gt;cluster.php&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Indention problem in function &lt;code&gt;getClusterChecks&lt;/code&gt; fixed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="load-balancer"&gt;Load Balancer&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Terms load-balancer and loadbalancer replaced by load balancer.&lt;/li&gt;
&lt;li&gt;User &lt;code&gt;radmin&lt;/code&gt; added for ProxySQL monitoring.&lt;/li&gt;
&lt;li&gt;Socket default for HAproxy changed to the new standards.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="virtual-ip-vipfloating-ip"&gt;Virtual IP (VIP)/Floating IP&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Status grey image does not exist in &lt;code&gt;vip_show_checks&lt;/code&gt;, fixed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="tools"&gt;Tools&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Crontab: Missing library in &lt;code&gt;check_instances.php&lt;/code&gt; added.&lt;/li&gt;
&lt;li&gt;Crontab: html tags removed in mail.&lt;/li&gt;
&lt;li&gt;Crontab: Error messages and error handling in crontab and start jobs improved, lock file directory is created automatically now.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="configuration"&gt;Configuration&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;No changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="database-as-a-service-dbaas"&gt;Database-as-a-Service (DBaaS)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;No changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="building-and-packaging"&gt;Building and Packaging&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Bulid moved to MyEnv project.&lt;/li&gt;
&lt;li&gt;Missing Rocky Linux branch added.&lt;/li&gt;
&lt;li&gt;Package &lt;code&gt;redhat-lsb-core&lt;/code&gt; does not exist on Rocky 9 any more, spec file adapted.&lt;/li&gt;
&lt;li&gt;Package build test fixed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="themes--ui"&gt;Themes / UI&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;jquery updated from 3.6.3 to 3.7.1&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="general"&gt;General&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Modification for license key automation added.&lt;/li&gt;
&lt;li&gt;Package installation &lt;code&gt;ssh-keygen&lt;/code&gt; is only called if key does not exist. So upgrade should work without error/warning.&lt;/li&gt;
&lt;li&gt;Some tests fixed, bug in &lt;code&gt;createPublicKey&lt;/code&gt; fixed.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;listRemoteDirectory&lt;/code&gt; does not write needlessly error messages any more.&lt;/li&gt;
&lt;li&gt;HTML tag placeholder added for add function, add object and save object made more error prone.&lt;/li&gt;
&lt;li&gt;Variable &lt;code&gt;tx_isolation&lt;/code&gt; replaced by &lt;code&gt;transaction_isolation&lt;/code&gt; which was deprecated in MariaDB 11.2 and MySQL 5.7.&lt;/li&gt;
&lt;li&gt;Code clean-up.&lt;/li&gt;
&lt;li&gt;Some menu items opened a new tab which was not intended. Fixed.&lt;/li&gt;
&lt;li&gt;Field naming made consistent.&lt;/li&gt;
&lt;li&gt;Error handling and error messages improved.&lt;/li&gt;
&lt;li&gt;Copyright year updated from 2023 to 2024.&lt;/li&gt;
&lt;li&gt;Message downgraded from &lt;code&gt;ERROR&lt;/code&gt; to &lt;code&gt;DEBUG&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;runRemoteCommand&lt;/code&gt; will return an error code again when &lt;code&gt;going_back_to&lt;/code&gt; functionality implemented.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;renderDropDown&lt;/code&gt; newline was removed.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;renderSubmitButton&lt;/code&gt; accepts a title now.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;runRemoteCommand&lt;/code&gt; can suppress error logging now.&lt;/li&gt;
&lt;li&gt;Command &lt;code&gt;apt-get&lt;/code&gt; replaced by &lt;code&gt;apt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Distribution information refactored.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;whoami&lt;/code&gt; cleaned-up.&lt;/li&gt;
&lt;li&gt;PHP 8.0 function calls removed again because of Debian 10/11 support.&lt;/li&gt;
&lt;li&gt;User interaction made unique among all 5 different objects.&lt;/li&gt;
&lt;li&gt;Redundant &lt;code&gt;DEBUG&lt;/code&gt; information removed.&lt;/li&gt;
&lt;li&gt;Configuration file was removed again when not needed any more (clean-up).&lt;/li&gt;
&lt;li&gt;Command &lt;code&gt;yum&lt;/code&gt; replaced by &lt;code&gt;dnf&lt;/code&gt;, also &lt;code&gt;apt-get&lt;/code&gt; partly.&lt;/li&gt;
&lt;li&gt;Command &lt;code&gt;which&lt;/code&gt; replaced by &lt;code&gt;type -p&lt;/code&gt; to make it Rocky 9 compliant.&lt;/li&gt;
&lt;li&gt;Some more &lt;code&gt;lsb_release&lt;/code&gt; stuff removed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;myEnv.inc&lt;/code&gt; library updated, &lt;code&gt;lsb_release&lt;/code&gt; removed.&lt;/li&gt;
&lt;li&gt;Dead code message added.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="repository"&gt;Repository&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;No changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="documentation"&gt;Documentation&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Version changed from 1.2.0 to 1.2.1 and TLS conflict on ubuntu 22.04 fixed.&lt;/li&gt;
&lt;li&gt;Build automatized.&lt;/li&gt;
&lt;li&gt;Documentation for M/S updated.&lt;/li&gt;
&lt;li&gt;All text taken over from CMS.&lt;/li&gt;
&lt;li&gt;Load balancer documentation added.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Ops Center Release Notes</title><link>https://www.fromdual.com/blog/ops-center-release-notes/</link><pubDate>Mon, 29 Apr 2024 16:42:39 +0200</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/ops-center-release-notes/</guid><description>&lt;ul&gt;
&lt;li&gt;Ops Center 1.2.2 &lt;a href="https://www.fromdual.com/blog/ops-center-release-notes/fromdual-ops-center-1.2.2-for-mariadb-mysql-and-compatible-databases-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 25 April 2024&lt;/li&gt;
&lt;li&gt;Ops Center 1.2.1 &lt;a href="https://www.fromdual.com/blog/ops-center-release-notes/fromdual-ops-center-1.2.1-for-mariadb-mysql-and-compatible-databases-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 7 Februray 2023&lt;/li&gt;
&lt;li&gt;Ops Center 1.2.0 &lt;a href="https://www.fromdual.com/blog/ops-center-release-notes/fromdual-ops-center-1.2.0-for-mariadb-mysql-and-compatible-databases-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 17 January 2023&lt;/li&gt;
&lt;li&gt;Ops Center 1.1.0 &lt;a href="https://www.fromdual.com/blog/ops-center-release-notes/fromdual-ops-center-1.1.0-for-mariadb-mysql-and-compatible-databases-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 7 May 2021&lt;/li&gt;
&lt;li&gt;Ops Center 1.0.0 &lt;a href="https://www.fromdual.com/blog/ops-center-release-notes/fromdual-ops-center-1.0.0-for-mariadb-mysql-and-compatible-databases-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 7 May 2020&lt;/li&gt;
&lt;li&gt;Ops Center 0.9.3 &lt;a href="https://www.fromdual.com/blog/ops-center-release-notes/fromdual-ops-center-for-mariadb-and-mysql-0.9.3-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 18 February 2020&lt;/li&gt;
&lt;li&gt;Ops Center 0.9.2 &lt;a href="https://www.fromdual.com/blog/ops-center-release-notes/fromdual-ops-center-for-mariadb-and-mysql-0.9.2-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 13 August 2019&lt;/li&gt;
&lt;li&gt;Ops Center 0.9.1 &lt;a href="https://www.fromdual.com/blog/ops-center-release-notes/fromdual-ops-center-for-mariadb-and-mysql-0.9.1-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 7 May 2019&lt;/li&gt;
&lt;li&gt;Ops Center 0.9.0 &lt;a href="https://www.fromdual.com/blog/ops-center-release-notes/fromdual-ops-center-for-mariadb-and-mysql-0.9-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 16 April 2019&lt;/li&gt;
&lt;li&gt;Ops Center 0.3.0 &lt;a href="https://www.fromdual.com/blog/ops-center-release-notes/fromdual-ops-center-for-mariadb-and-mysql-0.3-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 13 January 2016&lt;/li&gt;
&lt;li&gt;Ops Center 0.2.0 Release Notes, Release Date: 29 May 2014&lt;/li&gt;
&lt;li&gt;Ops Center 0.1.0 Release Notes, Release Date: 02 January 2014&lt;/li&gt;
&lt;li&gt;Ops Center 0.0.1 Release Notes, Release Date: 01 January 2014&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>dbstat for MariaDB after one month of productive use</title><link>https://www.fromdual.com/blog/dbstat-for-mariadb-after-one-month-of-productive-use/</link><pubDate>Fri, 26 Apr 2024 14:13:55 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/dbstat-for-mariadb-after-one-month-of-productive-use/</guid><description>&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-after-one-month-of-productive-use/#retrospect"&gt;Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-after-one-month-of-productive-use/#one-month-later"&gt;One month later&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-after-one-month-of-productive-use/#table-size"&gt;Size of the tables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-after-one-month-of-productive-use/#processlist"&gt;Process list&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-after-one-month-of-productive-use/#global-variables"&gt;Global variables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-after-one-month-of-productive-use/#locking"&gt;Metadata Lock and InnoDB Transaction Lock&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-after-one-month-of-productive-use/#global-status"&gt;Global status&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="review"&gt;Review&lt;/h2&gt;
&lt;p&gt;After we introduced &lt;a href="https://www.fromdual.com/dbstat-for-mariadb-and-mysql"&gt;&lt;code&gt;dbstat&lt;/code&gt; for MariaDB (and MySQL)&lt;/a&gt; a good 5 weeks ago, we naturally also rolled it out on our systems to test the behaviour in daily use (&lt;a href="https://en.wikipedia.org/wiki/Eating_your_own_dog_food" target="_blank" title="Eating your own dog food auf Wikipedia"&gt;eat your own dog food&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;This went quite well until we came up with the idea of activating &lt;code&gt;dbstat&lt;/code&gt; on the passive &lt;code&gt;dbstat&lt;/code&gt; node on our MariaDB active/passive master/master replication cluster (a similar situation would also occur with a Galera cluster). We realised that the design of &lt;code&gt;dbstat&lt;/code&gt; still had potential. After this problem was fixed (v0.0.2 and v0.0.3) and the problem of how to activate events on master AND slave was solved (&lt;a href="https://jira.mariadb.org/browse/MDEV-33782" target="_blank"&gt;MDEV-33782: Event is always disabled on slave&lt;/a&gt;), everything seemed fine at first glance. Unfortunately, we did not realise that the data also had to be adjusted. As a result, our replication came to a complete stop over the Easter holidays, which then led to another problem when catching up (&lt;a href="https://jira.mariadb.org/browse/MDEV-33923" target="_blank"&gt;MDEV-33923: MariaDB parallel replication causes Foreign Key errors&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;After this minor incident was also resolved, &lt;code&gt;dbstat&lt;/code&gt; has been running flawlessly on our MariaDB master/master replication cluster ever since&amp;hellip; The product &lt;code&gt;dbstat&lt;/code&gt; is open source (GPLv2) and can be &lt;a href="https://github.com/FromDual/dbstat" target="_blank" title="dbstat on GitHub"&gt;downloaded from GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="one-month-later"&gt;One month later&lt;/h2&gt;
&lt;p&gt;Databases should NOT grow over time but only over the number of {customers, products, etc.} once the desired equilibrium (&lt;a href="https://www.merriam-webster.com/dictionary/steady state" target="_blank"&gt;steady state&lt;/a&gt;) is reached. In our &lt;code&gt;dbstat&lt;/code&gt; installation, we have set this equilibrium state to 30 days. So it is now time that the size of &lt;code&gt;dbstat&lt;/code&gt; stabilises and the database stops growing&amp;hellip;&lt;/p&gt;
&lt;p&gt;It would also be interesting to understand what practical use &lt;code&gt;dbstat&lt;/code&gt; has. That is why we have now set to work and are trying to analyse the results of &lt;code&gt;dbstat&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here is an overview of the 11 current running database events:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SELECT db, name, definer, CONCAT(interval_value, ' ', interval_field) AS 'interval'
 , last_executed, ends, status
 FROM mysql.event
 ORDER BY db, name ASC
;
+--------+-------------------------+------------------+----------+---------------------+------+---------+
| db | name | definer | interval | last_executed | ends | status |
+--------+-------------------------+------------------+----------+---------------------+------+---------+
| dbstat | gather_global_status | dbstat@localhost | 1 MINUTE | 2024-04-24 07:44:14 | NULL | ENABLED |
| dbstat | gather_global_variables | dbstat@localhost | 1 MINUTE | 2024-04-24 07:44:32 | NULL | ENABLED |
| dbstat | gather_metadata_lock | dbstat@localhost | 1 MINUTE | 2024-04-24 07:44:47 | NULL | ENABLED |
| dbstat | gather_processlist | dbstat@localhost | 1 MINUTE | 2024-04-24 07:44:28 | NULL | ENABLED |
| dbstat | gather_table_size | dbstat@localhost | 1 DAY | 2024-04-24 00:04:00 | NULL | ENABLED |
| dbstat | gather_trx_and_lck | dbstat@localhost | 1 MINUTE | 2024-04-24 07:44:35 | NULL | ENABLED |
| dbstat | purge_global_status | dbstat@localhost | 1 MINUTE | 2024-04-24 07:44:08 | NULL | ENABLED |
| dbstat | purge_metadata_lock | dbstat@localhost | 5 MINUTE | 2024-04-24 07:44:37 | NULL | ENABLED |
| dbstat | purge_processlist | dbstat@localhost | 1 MINUTE | 2024-04-24 07:43:58 | NULL | ENABLED |
| dbstat | purge_table_size | dbstat@localhost | 5 MINUTE | 2024-04-24 07:40:04 | NULL | ENABLED |
| dbstat | purge_trx_and_lck | dbstat@localhost | 1 MINUTE | 2024-04-24 07:44:45 | NULL | ENABLED |
+--------+-------------------------+------------------+----------+---------------------+------+---------+
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="size-of-the-tables"&gt;Size of the tables&lt;/h2&gt;
&lt;p&gt;Firstly, the growth of &lt;code&gt;dbstat&lt;/code&gt; itself is interesting. But of course this evaluation can also be carried out for any other database, table or catalogue (&lt;a href="https://mariadb.com/kb/en/catalogs-overview" target="_blank"&gt;coming in MariaDB 11.7?&lt;/a&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SET SESSION sql_mode='STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,only_full_group_by';

SQL&amp;gt; SET @machine_name = @@hostname;

SQL&amp;gt; SELECT `table_schema`, SUBSTR(`ts`, 1, 10) AS date
 , ROUND(SUM(`data_length`)/1024/1024, 1) AS data_mb
 , ROUND(SUM(`index_length`)/1024/1024, 1) AS index_mb
 , ROUND(SUM(`data_free`)/1024/1024, 1) AS free_mb
 , ROUND((SUM(`data_length`) + SUM(`index_length`) + SUM(`data_free`))/1024/1024, 1) AS total_mb
 , ROUND(SUM(`table_rows`)/1000/1000, 1) AS rows_m
 FROM `table_size`
 WHERE `machine_name` = @machine_name
 AND `table_catalog` = 'def'
 AND `table_schema` = 'dbstat'
 GROUP BY `table_catalog`, `table_schema`, `date`
 ORDER BY `table_catalog`, `table_schema`, `date` ASC
;
+--------------+------------+---------+----------+---------+----------+--------+
| table_schema | date | data_mb | index_mb | free_mb | total_mb | rows_m |
+--------------+------------+---------+----------+---------+----------+--------+
| dbstat | 2024-03-26 | 762.8 | 1128.6 | 18.0 | 1909.4 | 10.9 |
| dbstat | 2024-03-27 | 835.8 | 1241.6 | 17.0 | 2094.4 | 11.1 |
| dbstat | 2024-03-28 | 837.8 | 1241.6 | 14.0 | 2093.4 | 11.8 |
| dbstat | 2024-03-29 | 960.7 | 1443.6 | 18.0 | 2422.4 | 14.2 |
| dbstat | 2024-03-30 | 960.7 | 1443.6 | 17.0 | 2421.4 | 15.0 |
| dbstat | 2024-03-31 | 1057.7 | 1604.6 | 20.0 | 2682.4 | 16.9 |
| dbstat | 2024-04-01 | 1057.7 | 1602.6 | 21.0 | 2681.4 | 17.6 |
| dbstat | 2024-04-02 | 1172.7 | 1797.6 | 22.0 | 2992.3 | 17.8 |
| dbstat | 2024-04-03 | 1442.8 | 2333.7 | 12.0 | 3788.5 | 22.8 |
| dbstat | 2024-04-04 | 1649.8 | 2723.7 | 13.0 | 4386.5 | 24.4 |
| dbstat | 2024-04-05 | 1649.8 | 2722.7 | 14.0 | 4386.5 | 26.0 |
| dbstat | 2024-04-06 | 1821.8 | 3034.8 | 13.0 | 4869.6 | 24.6 |
| dbstat | 2024-04-07 | 1821.8 | 3034.8 | 14.0 | 4870.6 | 26.2 |
| dbstat | 2024-04-08 | 1989.9 | 3344.8 | 12.0 | 5346.6 | 29.9 |
| dbstat | 2024-04-09 | 1990.9 | 3343.8 | 14.0 | 5348.6 | 31.5 |
| dbstat | 2024-04-10 | 2193.9 | 3712.8 | 13.0 | 5919.7 | 31.6 |
| dbstat | 2024-04-11 | 2193.9 | 3712.8 | 15.0 | 5921.7 | 31.1 |
| dbstat | 2024-04-12 | 2405.8 | 4119.1 | 12.0 | 6537.0 | 34.9 |
| dbstat | 2024-04-13 | 2405.8 | 4119.1 | 14.0 | 6538.9 | 35.7 |
| dbstat | 2024-04-14 | 2480.8 | 4278.9 | 15.0 | 6774.8 | 36.2 |
| dbstat | 2024-04-15 | 2560.8 | 4443.7 | 12.0 | 7016.5 | 37.5 |
| dbstat | 2024-04-16 | 2560.8 | 4443.7 | 12.0 | 7016.5 | 38.2 |
| dbstat | 2024-04-17 | 2640.8 | 4610.6 | 18.0 | 7269.4 | 38.5 |
| dbstat | 2024-04-18 | 2640.9 | 4611.6 | 14.0 | 7266.5 | 39.7 |
| dbstat | 2024-04-19 | 2743.9 | 4826.5 | 14.0 | 7584.3 | 36.9 |
| dbstat | 2024-04-20 | 2826.9 | 4995.5 | 14.0 | 7836.4 | 38.3 |
| dbstat | 2024-04-21 | 2830.9 | 4997.4 | 18.0 | 7846.3 | 39.2 |
| dbstat | 2024-04-22 | 2919.9 | 5177.4 | 14.0 | 8111.3 | 43.2 |
| dbstat | 2024-04-23 | 2923.0 | 5177.3 | 16.0 | 8116.3 | 44.1 |
| dbstat | 2024-04-24 | 3020.0 | 5376.3 | 16.0 | 8412.3 | 41.0 |
| dbstat | 2024-04-25 | 3024.0 | 5377.3 | 17.0 | 8418.3 | 40.9 |
+--------------+------------+---------+----------+---------+----------+--------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you take the disc space in the O/S for comparison:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# du -shc *.ibd
8.6G global_status.ibd
308K global_variables.ibd
692K metadata_lock.ibd
97M processlist.ibd
18M table_size.ibd
212K trx_and_lck.ibd
8.7G total
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;you can see that the values from the database are approximately correct (5% error)&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.fromdual.com/sites/default/files/size_of_db_dbstat.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: The database &lt;code&gt;dbstat&lt;/code&gt; reaches a size of approx. 9 Gbyte after approx. one month on a not particularly large database system.&lt;/p&gt;
&lt;p&gt;You can also see that the size of the database is only just stabilising:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.fromdual.com/sites/default/files/number_of_rows.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;If you want to know more precisely which tables are responsible for which part of the data volume, you can also zoom in or &lt;a href="https://www.dictionary.com/browse/drill-down" target="_blank"&gt;drill down&lt;/a&gt; into the data:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SELECT `table_name`, SUBSTR(`ts`, 1, 10) AS date
 , ROUND(`data_length`/1024/1024, 1) AS data_mb
 , ROUND(`index_length`/1024/1024, 1) AS index_mb
 , ROUND(`data_free`/1024/1024, 1) AS free_mb
 , ROUND((`data_length` + `index_length` + `data_free`)/1024/1024, 1) AS total_mb
 , ROUND((`data_length` + `index_length` + `data_free`)/1024/1024/8418.26*100, 1) AS pct
 , ROUND(`table_rows`/1000/1000, 1) AS rows_m
 FROM `table_size`
 WHERE `machine_name` = @machine_name
 AND `table_catalog` = 'def'
 AND `table_schema` = 'dbstat'
 AND SUBSTR(`ts`, 1, 10) = CURRENT_DATE()
 ORDER BY rows_m DESC
;
+------------------+------------+---------+----------+---------+----------+------+--------+
| table_name | date | data_mb | index_mb | free_mb | total_mb | pct | rows_m |
+------------------+------------+---------+----------+---------+----------+------+--------+
| global_status | 2024-04-25 | 2949.9 | 5356.9 | 5.0 | 8311.8 | 98.7 | 40.4 |
| processlist | 2024-04-25 | 68.2 | 17.1 | 7.0 | 92.2 | 1.1 | 0.4 |
| global_variables | 2024-04-25 | 0.1 | 0.1 | 0.0 | 0.2 | 0.0 | 0.0 |
| metadata_lock | 2024-04-25 | 0.4 | 0.2 | 0.0 | 0.6 | 0.0 | 0.0 |
| table_size | 2024-04-25 | 5.4 | 3.1 | 5.0 | 13.5 | 0.2 | 0.0 |
| trx_and_lck | 2024-04-25 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
+------------------+------------+---------+----------+---------+----------+------+--------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Please excuse the non-use of the window function!&lt;/p&gt;
&lt;p&gt;The only real driver for the data volume of this database is the &lt;code&gt;global_status&lt;/code&gt; table. This is to be expected (see: &lt;a href="https://www.fromdual.com/dbstat-fuer-mariadb-und-mysql#how-does-dbstat-work"&gt;see quantity structure of &lt;code&gt;dbstat&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SELECT SUBSTR(ts, 1, 10) AS date, table_rows/1000/1000 AS k_rows
 , ROUND(data_length/1024/1024, 1) AS data_mb, ROUND(index_length/1024/1024, 1) AS index_mb, ROUND(data_free/1024/1024, 1) AS free_mb
 , ROUND((data_length + index_length + data_free)/1024/1024, 1) AS total_mb
 FROM table_size
 WHERE `machine_name` = @machine_name
 AND `table_catalog` = 'def'
 AND `table_schema` = 'dbstat'
 AND table_name = 'global_status'
 AND ts &amp;gt; DATE_SUB(CURRENT_DATE, INTERVAL 10 DAY)
;
+------------+-------------+---------+----------+---------+----------+
| date | k_rows | data_mb | index_mb | free_mb | total_mb |
+------------+-------------+---------+----------+---------+----------+
| 2024-04-15 | 37.13876300 | 2512.9 | 4433.0 | 4.0 | 6949.9 |
| 2024-04-16 | 37.94217200 | 2512.9 | 4433.0 | 4.0 | 6949.9 | + 0M
| 2024-04-17 | 38.19867500 | 2592.9 | 4600.0 | 7.0 | 7199.9 | + 250M
| 2024-04-18 | 39.39108500 | 2592.9 | 4600.0 | 5.0 | 7197.9 | - 2M
| 2024-04-19 | 36.52539600 | 2691.9 | 4813.0 | 5.0 | 7509.8 | + 312M
| 2024-04-20 | 37.99073500 | 2770.9 | 4980.9 | 6.0 | 7757.8 | + 248M
| 2024-04-21 | 38.79420200 | 2770.9 | 4980.9 | 7.0 | 7758.8 | + 1M
| 2024-04-22 | 42.82606200 | 2855.9 | 5158.9 | 6.0 | 8020.8 | + 263M
| 2024-04-23 | 43.62953000 | 2855.9 | 5158.9 | 7.0 | 8021.8 | + 1M
| 2024-04-24 | 40.54342200 | 2949.9 | 5356.9 | 7.0 | 8313.8 | + 292M
| 2024-04-25 | 40.43067700 | 2949.9 | 5356.9 | 5.0 | 8311.8 | - 2M
+------------+-------------+---------+----------+---------+----------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Sorry, I should really familiarise myself with the window functions&amp;hellip;&lt;/p&gt;
&lt;p&gt;If we analyse the data a bit more closely, we see that the number of rows has slowly stabilised over the last 4 days (note: &lt;code&gt;table_rows&lt;/code&gt; is calculated (from the number of blocks and the average row length?) and is not an exact value), but the &amp;ldquo;amount of data&amp;rdquo; has continued to increase until yesterday, which is probably due to the fragmentation of the tables and indexes&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.fromdual.com/sites/default/files/size_per_table.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;The primary key of the &lt;code&gt;global_status&lt;/code&gt; table was chosen to optimise the &lt;a href="https://en.wikipedia.org/wiki/Locality_of_reference" target="_blank" title="Locality of reference on Wikipedia"&gt;localisation of the data&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PRIMARY KEY (`machine_name`,`variable_name`,`ts`),
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The situation should calm down in the next few days. In 2 to 4 weeks we will have to check the situation again.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;: I would say that this feature fulfils the requirements and helps to understand the data growth.&lt;/p&gt;
&lt;h2 id="list-of-processes"&gt;List of processes&lt;/h2&gt;
&lt;p&gt;Since we do not have any serious load issues in our databases, this feature is not that interesting in our case. For example, we can see what a (persistent) connection has done:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SELECT connection_id, ts, command, time, state, SUBSTR(REGEXP_REPLACE(REPLACE(query, &amp;quot;&amp;lt;br&amp;gt;n&amp;quot;, ' '), '&amp;lt;br&amp;gt; +', ' '), 1, 64)
 FROM processlist
 WHERE machine_name = @machine_name
 AND command != 'Sleep'
 AND connection_id = @connection_id
 AND state NOT IN (
 'Waiting for next activation'
 , 'Master has sent all binlog to slave; waiting for more updates'
 , 'Waiting for master to send event'
 , 'Slave has read all relay log; waiting for more updates'
 )
 ORDER BY ts ASC
;
+---------------+---------------------+---------+-------+----------------+----------------------------------------------------------------------+
| connection_id | ts | command | time | state | SUBSTR(REGEXP_REPLACE(REPLACE(query, &amp;quot;&amp;lt;br&amp;gt;n&amp;quot;, ' '), '&amp;lt;br&amp;gt; +', ' '), 1, 64) |
+---------------+---------------------+---------+-------+----------------+----------------------------------------------------------------------+
| 18 | 2024-04-17 12:30:28 | Query | 0.029 | Sending data | select pp.item_preprocid,pp.itemid,pp.type,pp.params,pp.step,h.h |
| 18 | 2024-04-17 14:58:28 | Query | 0.009 | Writing to net | select itemtagid,itemid,tag,value from item_tag |
| 18 | 2024-04-18 06:24:28 | Query | 0.003 | Sending data | select pp.item_preprocid,pp.itemid,pp.type,pp.params,pp.step,h.h |
| 18 | 2024-04-18 11:34:28 | Query | 0.030 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-18 16:39:28 | Query | 0.006 | Sending data | select itemid,functionid,name,parameter,triggerid from functions |
| 18 | 2024-04-18 19:12:28 | Query | 0.014 | Sending data | select triggerid,description,expression,error,priority,type,valu |
| 18 | 2024-04-18 21:49:28 | Query | 0.004 | Writing to net | select i.itemid,i.hostid,i.templateid from items i inner join ho |
| 18 | 2024-04-19 00:21:28 | Query | 0.032 | Sending data | select pp.item_preprocid,pp.itemid,pp.type,pp.params,pp.step,h.h |
| 18 | 2024-04-19 02:59:28 | Query | 0.017 | Writing to net | select triggerid,description,expression,error,priority,type,valu |
| 18 | 2024-04-19 05:39:28 | Query | 0.052 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-19 08:19:28 | Query | 0.000 | Statistics | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-19 13:26:28 | Query | 0.075 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-19 15:57:28 | Query | 0.027 | Writing to net | select itemtagid,itemid,tag,value from item_tag |
| 18 | 2024-04-19 18:33:28 | Query | 0.010 | Sending data | select itemtagid,itemid,tag,value from item_tag |
| 18 | 2024-04-19 21:10:28 | Query | 0.008 | Sending data | select pp.item_preprocid,pp.itemid,pp.type,pp.params,pp.step,h.h |
| 18 | 2024-04-19 23:50:28 | Query | 0.067 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-20 02:28:28 | Query | 0.008 | Sending data | select triggerid,description,expression,error,priority,type,valu |
| 18 | 2024-04-20 05:08:28 | Query | 0.052 | Writing to net | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-20 07:44:28 | Query | 0.123 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-20 10:21:28 | Query | 0.144 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-20 12:55:28 | Query | 0.004 | Sending data | select i.itemid,i.hostid,i.templateid from items i where i.flags |
| 18 | 2024-04-20 15:35:28 | Query | 0.092 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-20 18:12:28 | Query | 0.041 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-20 20:47:28 | Query | 0.113 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-20 23:25:28 | Query | 0.101 | Writing to net | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-21 02:03:28 | Query | 0.120 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-21 04:42:28 | Query | 0.099 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-21 07:18:28 | Query | 0.015 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-21 12:32:28 | Query | 0.018 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-21 15:06:28 | Query | 0.091 | Writing to net | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-21 20:16:28 | Query | 0.012 | Sending data | select itemtagid,itemid,tag,value from item_tag |
| 18 | 2024-04-22 06:44:28 | Query | 0.161 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-22 09:21:28 | Query | 0.000 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-22 11:54:28 | Query | 0.020 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-22 14:23:28 | Query | 0.067 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-22 16:59:28 | Query | 0.128 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-22 22:05:28 | Query | 0.078 | Writing to net | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-23 00:38:28 | Query | 0.084 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-23 03:15:28 | Query | 0.098 | Writing to net | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-23 05:52:28 | Query | 0.000 | starting | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-23 08:27:28 | Query | 0.011 | Sending data | select pp.item_preprocid,pp.itemid,pp.type,pp.params,pp.step,h.h |
| 18 | 2024-04-23 10:58:28 | Query | 0.000 | Sending data | select i.itemid,i.hostid,i.templateid from items i inner join ho |
| 18 | 2024-04-23 13:31:28 | Query | 0.110 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-23 16:01:28 | Query | 0.023 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-23 18:35:28 | Query | 0.095 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-23 21:10:28 | Query | 0.017 | Writing to net | select itemtagid,itemid,tag,value from item_tag |
| 18 | 2024-04-23 23:44:28 | Query | 0.014 | Sending data | select triggerid,description,expression,error,priority,type,valu |
| 18 | 2024-04-24 02:21:28 | Query | 0.024 | Sending data | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
| 18 | 2024-04-24 07:33:28 | Query | 0.046 | Writing to net | select i.itemid,i.hostid,i.status,i.type,i.value_type,i.key_,i.s |
+---------------+---------------------+---------+-------+----------------+----------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is also important that we only see the entries in this report when the thread has done SOMETHING (we have hidden state &lt;code&gt;Sleep&lt;/code&gt;). It is also interesting that we do not see this (persistent) connection before 17 April, but at the moment I have NO explanation for this from an operational point of view (restart etc.). Probably the application (Zabbix) has to explain this.&lt;/p&gt;
&lt;h2 id="global-variables"&gt;Global variables&lt;/h2&gt;
&lt;p&gt;The information in the &lt;code&gt;global_variables&lt;/code&gt; table is also interesting:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SELECT variable_name, ts, variable_value
 FROM global_variables
 WHERE machine_name = @machine_name
 AND variable_name IN (
 SELECT variable_name
 FROM global_variables
 WHERE machine_name = @machine_name
 GROUP BY variable_name
 HAVING COUNT(*) &amp;gt; 1
 )
 ORDER BY ts, variable_name
;
+---------------------------+---------------------+----------------+
| variable_name | ts | variable_value |
+---------------------------+---------------------+----------------+
| auto_increment_increment | 2024-03-09 22:10:42 | 1 |
| auto_increment_offset | 2024-03-09 22:10:42 | 1 |
| read_only | 2024-03-09 22:10:42 | OFF |
| slave_parallel_max_queued | 2024-03-09 22:10:42 | 131072 |
| slave_parallel_threads | 2024-03-09 22:10:42 | 0 |
| slave_parallel_workers | 2024-03-09 22:10:42 | 0 |
| slave_skip_errors | 2024-03-09 22:10:42 | OFF |
| system_time_zone | 2024-03-09 22:10:42 | CET |

| read_only | 2024-03-27 09:42:50 | ON |
| slave_skip_errors | 2024-03-27 12:33:13 | 1032 |
| slave_skip_errors | 2024-03-27 12:35:13 | OFF |
| slave_skip_errors | 2024-03-27 12:42:13 | 1032 |
| slave_skip_errors | 2024-03-27 12:50:13 | OFF |

| slave_parallel_threads | 2024-04-02 10:17:32 | 8 |
| slave_parallel_workers | 2024-04-02 10:17:32 | 8 |
| slave_parallel_max_queued | 2024-04-02 10:22:32 | 1048576 |
| slave_parallel_max_queued | 2024-04-02 10:23:32 | 4194304 |
| slave_parallel_max_queued | 2024-04-02 10:25:32 | 16777216 |
| slave_parallel_threads | 2024-04-02 10:25:32 | 16 |
| slave_parallel_workers | 2024-04-02 10:25:32 | 16 |
| slave_parallel_threads | 2024-04-02 10:28:32 | 32 |
| slave_parallel_workers | 2024-04-02 10:28:32 | 32 |
| auto_increment_increment | 2024-04-02 10:39:32 | 2 |
| auto_increment_offset | 2024-04-02 10:39:32 | 2 |
| slave_parallel_max_queued | 2024-04-02 10:57:32 | 131072 |
| slave_parallel_threads | 2024-04-02 10:57:32 | 0 |
| slave_parallel_workers | 2024-04-02 10:57:32 | 0 |
| system_time_zone | 2024-04-02 10:57:32 | CEST |

| slave_parallel_max_queued | 2024-04-16 14:06:32 | 16777216 |
| slave_parallel_threads | 2024-04-16 14:06:32 | 8 |
| slave_parallel_workers | 2024-04-16 14:06:32 | 8 |
| slave_parallel_max_queued | 2024-04-16 14:26:32 | 131072 |
| slave_parallel_threads | 2024-04-16 14:26:32 | 0 |
| slave_parallel_workers | 2024-04-16 14:26:32 | 0 |

| slave_parallel_max_queued | 2024-04-17 09:03:32 | 16777216 |
| slave_parallel_threads | 2024-04-17 09:03:32 | 16 |
| slave_parallel_workers | 2024-04-17 09:03:32 | 16 |

| slave_parallel_max_queued | 2024-04-24 08:26:32 | 131072 |
| slave_parallel_threads | 2024-04-24 08:26:32 | 0 |
| slave_parallel_workers | 2024-04-24 08:26:32 | 0 |
| read_only | 2024-04-24 08:42:32 | OFF |
+---------------------------+---------------------+----------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here you can see very precisely when and what was done to the database:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On 9 March, &lt;code&gt;dbstat&lt;/code&gt; was installed for the first time.&lt;/li&gt;
&lt;li&gt;Then on 27 March (before Easter) there seem to have been problems with the replication (here the new version of &lt;code&gt;dbstat&lt;/code&gt; was installed, which allows simultaneous collection on master and slave. This led to replication errors, which were partially rectified).&lt;/li&gt;
&lt;li&gt;On 2 April (after Easter) we then tried to catch up with parallel replication. You can also see that &lt;code&gt;AUTO_INCREMENT_OFFSET&lt;/code&gt; and &lt;code&gt;AUTO_INCREMENT_INCREMENT&lt;/code&gt; have been changed. Here we have corrected an error in the database configuration&amp;hellip;&lt;/li&gt;
&lt;li&gt;You can also see that the time zone has changed from &lt;code&gt;CET&lt;/code&gt; to &lt;code&gt;CEST&lt;/code&gt; (summer time!) Why only on 2 April is not entirely clear to me. (Maybe because it came via replication?)&lt;/li&gt;
&lt;li&gt;Then on 16 and 17 April we tried to reproduce a &amp;ldquo;bug&amp;rdquo; in the parallel replication. Apparently we did not reset the value. Because only after the restart on 24 April (usual fortnightly maintenance window) was the value reset again.&lt;/li&gt;
&lt;li&gt;On 24 April, you can also see that the database has now assumed the role of the active master (&lt;code&gt;read_only = off&lt;/code&gt;). A gracefull switchover has therefore taken place&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;: A very useful feature to see when something has been changed. Although I have followed all these operations closely, I am still amazed at the informative value of this feature. I would like to see it installed in all databases&amp;hellip;&lt;/p&gt;
&lt;h2 id="metadata-lock-and-innodb-transaction-lock"&gt;Metadata Lock and InnoDB Transaction Lock&lt;/h2&gt;
&lt;p&gt;Unfortunately, due to the low traffic on our databases, we do not see too much exciting stuff here.&lt;/p&gt;
&lt;p&gt;Here are the metadata locks that we have &amp;ldquo;caught&amp;rdquo; on the master in the last 24 hours:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;+---------------+---------------------+--------+-----------------+--------------+---------------+-----------------+----------------------------------------------------------------------+
| connection_id | ts | user | host | table_schema | table_name | state | SUBSTR(REGEXP_REPLACE(REPLACE(query, &amp;quot;&amp;lt;br&amp;gt;n&amp;quot;, ' '), '&amp;lt;br&amp;gt; +', ' '), 1, 64) |
+---------------+---------------------+--------+-----------------+--------------+---------------+-----------------+----------------------------------------------------------------------+
| 18 | 2024-04-23 14:16:47 | zabbix | localhost:51252 | zabbix | triggers | Writing to net | select triggerid,description,expression,error,priority,type,valu |
| 1325025 | 2024-04-23 16:01:47 | zabbix | localhost:50150 | | | init for update | delete from history_text where itemid=85477 and clock&amp;lt;1678167661 |
| 1325025 | 2024-04-23 16:01:47 | zabbix | localhost:50150 | zabbix | history_text | init for update | delete from history_text where itemid=85477 and clock&amp;lt;1678167661 |
| 1365229 | 2024-04-24 02:13:47 | root | localhost:38096 | dbstat | global_status | Writing to net | SELECT /*!40001 SQL_NO_CACHE */ `machine_name`, `variable_name`, |
| 18 | 2024-04-24 03:10:47 | zabbix | localhost:51252 | zabbix | item_tag | Writing to net | select itemtagid,itemid,tag,value from item_tag |
| 1368524 | 2024-04-24 04:41:47 | zabbix | localhost:38112 | | | | NULL |
| 1368524 | 2024-04-24 04:41:47 | zabbix | localhost:38112 | zabbix | history_uint | | NULL |
| 18 | 2024-04-24 05:46:47 | zabbix | localhost:51252 | zabbix | item_tag | Sending data | select itemtagid,itemid,tag,value from item_tag |
+---------------+---------------------+--------+-----------------+--------------+---------------+-----------------+----------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We have not found any InnoDB locks in the last 24 hours for 7 days in a row.&lt;/p&gt;
&lt;p&gt;It would be interesting to see a system where more is happening&amp;hellip;&lt;/p&gt;
&lt;h2 id="global-status"&gt;Global status&lt;/h2&gt;
&lt;p&gt;If a normal database monitoring such as the &lt;a href="https://www.fromdual.com/fromdual-performance-monitor" target="_blank"&gt;FromDual Performance Monitor for MariaDB and MySQL&lt;/a&gt; (fpmmm) with Zabbix is used, this feature is not absolutely necessary. However, most of our customers do not have any useful monitoring in use. Therefore, this feature would be very useful for post-mortem analyses&amp;hellip;&lt;/p&gt;
&lt;p&gt;For example InnoDB Row Lock Waits, minute-granular over the last 30 days (analogue to &lt;code&gt;sar&lt;/code&gt; from &lt;code&gt;sysstat&lt;/code&gt;):&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.fromdual.com/sites/default/files/innodb_row_lock_waits.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Here you can see that the database was restarted on 10 April between 08:37 and 08:41. You could also find this out in another way, but unfortunately this is often not possible for various reasons (error log rotated away, etc.).&lt;/p&gt;
&lt;p&gt;The trend break around 2 April is also interesting. At this time we were experimenting with parallel replication. It should not have been a failover (see GLOBAL VARIABLES, above).&lt;/p&gt;
&lt;p&gt;Although parallel replication was later deactivated again, there were more locks. A similar situation around the 16th/17th of April, here too we played around with parallel replication, which seems to have had an effect on the locking behaviour.&lt;/p&gt;
&lt;p&gt;Even with this feature, there are many ways to analyse the database. Unfortunately, our database is relatively boring: Mainly monotonous traffic (which is plentiful due to the monitoring) and very little exceptional traffic.&lt;/p&gt;
&lt;p&gt;Remark: This text has been translated with the assistance of &lt;a href="https://www.deepl.com/" target="_blank"&gt;DeepL&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>MariaDB's parallel replication to catch up</title><link>https://www.fromdual.com/blog/mariadbs-parallel-replication-to-catch-up/</link><pubDate>Tue, 09 Apr 2024 10:53:32 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/mariadbs-parallel-replication-to-catch-up/</guid><description>&lt;p&gt;Due to an application error, our replication stopped for 5 days (over Easter). After the problem was solved, the replication was supposed to catch up, which turned out to be very slow. All the usual tricks (&lt;code&gt;innodb_flush_log_at_trx_commit&lt;/code&gt;, &lt;code&gt;sync_binlog&lt;/code&gt;, etc.) had already been exhausted. So we tried our hand at parallel replication of the MariaDB server.&lt;/p&gt;
&lt;p&gt;Parallel replication is deactivated by default:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SHOW GLOBAL VARIABLES LIKE '%parallel%';
+-------------------------------+------------+
| Variable_name | Value |
+-------------------------------+------------+
| slave_domain_parallel_threads | 0 |
| slave_parallel_max_queued | 131072 |
| slave_parallel_mode | optimistic |
| slave_parallel_threads | 0 |
| slave_parallel_workers | 0 |
+-------------------------------+------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Parallel replication is activated by setting the server variables &lt;code&gt;slave_parallel_threads&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SET GLOBAL slave_parallel_threads = 8;
ERROR 1198 (HY000): This operation cannot be performed as you have a running slave ''; run STOP SLAVE '' first
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, this must be done when replication is stopped:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; STOP SLAVE;
SQL&amp;gt; SET GLOBAL slave_parallel_threads = 8;
SQL&amp;gt; START SLAVE;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replication then caught up a little faster. However, as we were impatient, we tried to make it even faster. With the command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SHOW SLAVE STATUS&amp;lt;br&amp;gt;G
...
Slave_SQL_Running_State: Waiting for room in worker thread event queue
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;we found the following message. You would also see it using the &lt;code&gt;SHOW PROCESSLIST&lt;/code&gt; command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SHOW PROCESSLIST;
+--------+-------------+- ... -+-----------+------+-----------------------------------------------+- ... -+
| Id | User | ... | Command | Time | State | ... |
+--------+-------------+- ... -+-----------+------+-----------------------------------------------+- ... -+
... ... ...
| 212496 | system user | ... | Slave_SQL | 16 | Waiting for room in worker thread event queue | ... |
+--------+-------------+- ... -+-----------+------+-----------------------------------------------+- ... -+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;According to the documentation, it can help in this case to increase the size of the &lt;code&gt;slave_parallel_max_queued&lt;/code&gt; variable slightly (attention: Oom!).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; STOP SLAVE;
SQL&amp;gt; SET GLOBAL slave_parallel_max_queued = 1*1024*1024;
SQL&amp;gt; SHOW GLOBAL VARIABLES LIKE '%parallel%';
+-------------------------------+------------+
| Variable_name | Value |
+-------------------------------+------------+
| slave_domain_parallel_threads | 0 |
| slave_parallel_max_queued | 1048576 |
| slave_parallel_mode | optimistic |
| slave_parallel_threads | 8 |
| slave_parallel_workers | 8 |
+-------------------------------+------------+
SQL&amp;gt; START SLAVE;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We have played around with the values &lt;code&gt;slave_parallel_threads&lt;/code&gt; in the range from 4 to 32 (with 8 vCores) and with &lt;code&gt;slave_parallel_max_queued&lt;/code&gt; in the range from 128 kbyte to 32 Mbyte.
&lt;strong&gt;Caution&lt;/strong&gt;: Do not exaggerate: 32 threads x 32 Mbyte = 1 Gbyte RAM (Oom)!&lt;/p&gt;
&lt;p&gt;To find out which values are the optimum, you would have to test and measure more extensively. In any case, the replication made up the 5-day backlog after about an hour, towards the end a little more than at the beginning, which was hopefully caused by our configuration adjustments.&lt;/p&gt;
&lt;img src="https://www.fromdual.com/sites/default/files/slave_lag_parallel_replication.png" width="640" /&gt;
&lt;p&gt;Depending on what DML statements are currently running, you can see that all threads can be used or that some threads have to wait for other threads:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SHOW PROCESSLIST;
+--------+-----------------+--------------+--------+---------------------------------------------------------------+------------+
| Id | User | Command | Time | State | Info |
+--------+-----------------+--------------+--------+---------------------------------------------------------------+------------+
| 2 | event_scheduler | Daemon | 506179 | Waiting for next activation | NULL |
| 191154 | root | Query | 0 | starting | show pr... |
| 208669 | replication | Binlog Dump | 297 | Master has sent all binlog to slave; waiting for more updates | NULL |
| 212495 | system user | Slave_IO | 20 | Waiting for master to send event | NULL |
| 212497 | system user | Slave_worker | 0 | Waiting for prior transaction to commit | NULL |
| 212498 | system user | Slave_worker | 0 | Waiting for prior transaction to commit | NULL |
| 212499 | system user | Slave_worker | 0 | Waiting for prior transaction to commit | NULL |
| 212500 | system user | Slave_worker | 0 | Waiting for prior transaction to commit | NULL |
| 212501 | system user | Slave_worker | 0 | Write_rows_log_event::write_row(-1) on table `history_uint` | insert ... |
| 212502 | system user | Slave_worker | 0 | Write_rows_log_event::write_row(-1) on table `history_uint` | insert ... |
| 212503 | system user | Slave_worker | 0 | Write_rows_log_event::write_row(-1) on table `history_str` | insert ... |
| 212504 | system user | Slave_worker | 0 | Waiting for prior transaction to commit | NULL |
| 212505 | system user | Slave_worker | 0 | Waiting for prior transaction to commit | NULL |
| 212506 | system user | Slave_worker | 0 | Waiting for prior transaction to commit | NULL |
| 212507 | system user | Slave_worker | 0 | Waiting for prior transaction to commit | NULL |
| 212510 | system user | Slave_worker | 0 | Waiting for prior transaction to commit | NULL |
| 212509 | system user | Slave_worker | 0 | Waiting for prior transaction to commit | NULL |
| 212508 | system user | Slave_worker | 0 | Waiting for prior transaction to commit | NULL |
| 212511 | system user | Slave_worker | 0 | Waiting for prior transaction to commit | NULL |
| 212512 | system user | Slave_worker | 0 | Waiting for prior transaction to commit | NULL |
| 212496 | system user | Slave_SQL | 16 | Waiting for room in worker thread event queue | NULL |
+--------+-----------------+--------------+--------+---------------------------------------------------------------+------------+

SQL&amp;gt; SHOW PROCESSLIST;
+--------+-----------------+--------------+--------+---------------------------------------------------------------+------------+
| Id | User | Command | Time | State | Info |
+--------+-----------------+--------------+--------+---------------------------------------------------------------+------------+
| 2 | event_scheduler | Daemon | 506197 | Waiting for next activation | NULL |
| 191154 | root | Query | 0 | starting | show pr... |
| 208669 | replication | Binlog Dump | 315 | Master has sent all binlog to slave; waiting for more updates | NULL |
| 212495 | system user | Slave_IO | 37 | Waiting for master to send event | NULL |
| 212497 | system user | Slave_worker | 0 | Delete_rows_log_event::ha_delete_row(-1) on table `history` | delete ... |
| 212498 | system user | Slave_worker | 0 | Delete_rows_log_event::find_row(-1) on table `history` | delete ... |
| 212499 | system user | Slave_worker | 0 | Delete_rows_log_event::ha_delete_row(-1) on table `history` | delete ... |
| 212500 | system user | Slave_worker | 0 | Delete_rows_log_event::find_row(-1) on table `history` | delete ... |
| 212501 | system user | Slave_worker | 0 | Delete_rows_log_event::find_row(-1) on table `history` | delete ... |
| 212502 | system user | Slave_worker | 0 | Delete_rows_log_event::find_row(-1) on table `history` | delete ... |
| 212503 | system user | Slave_worker | 0 | Delete_rows_log_event::find_row(-1) on table `history` | delete ... |
| 212504 | system user | Slave_worker | 0 | Delete_rows_log_event::ha_delete_row(-1) on table `history` | delete ... |
| 212505 | system user | Slave_worker | 0 | Delete_rows_log_event::find_row(-1) on table `history` | delete ... |
| 212506 | system user | Slave_worker | 0 | Delete_rows_log_event::ha_delete_row(-1) on table `history` | delete ... |
| 212507 | system user | Slave_worker | 0 | Delete_rows_log_event::find_row(-1) on table `history` | delete ... |
| 212510 | system user | Slave_worker | 0 | Delete_rows_log_event::find_row(-1) on table `history` | delete ... |
| 212509 | system user | Slave_worker | 0 | Delete_rows_log_event::find_row(-1) on table `history` | delete ... |
| 212508 | system user | Slave_worker | 0 | Delete_rows_log_event::find_row(-1) on table `history` | delete ... |
| 212511 | system user | Slave_worker | 0 | Delete_rows_log_event::find_row(-1) on table `history` | delete ... |
| 212512 | system user | Slave_worker | 0 | Delete_rows_log_event::find_row(-1) on table `history` | delete ... |
| 212496 | system user | Slave_SQL | 11 | Waiting for room in worker thread event queue | NULL |
+--------+-----------------+--------------+--------+---------------------------------------------------------------+------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our monitoring also showed us that the CPU load went up, the I/O system got more to do and more rows were modified&amp;hellip;&lt;/p&gt;
&lt;img src="https://www.fromdual.com/sites/default/files/slave_lag_cpu.png" width="640" /&gt;
&lt;img src="https://www.fromdual.com/sites/default/files/slave_lag_io.png" width="640" /&gt;
&lt;img src="https://www.fromdual.com/sites/default/files/slave_lag_handler.png" width="640" /&gt;
&lt;p&gt;What was also noticeable is that with parallel replication, Foreign Key errors suddenly occurred, a phenomenon that we had not observed before:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FromDual.maas2.prod2 - Warning: InnoDB Foreign Key error detected

Trigger: InnoDB Foreign Key error detected
Trigger status: PROBLEM
Trigger severity: Warning
Trigger URL: https://fromdual.com/innodb-foreign-key-error-detected

Item values: 1

1. InnoDB new Foreign Key error (FromDual.maas2.prod2:FromDual.MySQL.innodb.ForeignKey_new): 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the command &lt;code&gt;SHOW ENGINE INNODB STATUS&amp;lt;br&amp;gt;G&lt;/code&gt; you can inspect these accordingly or view them in the monitoring:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;------------------------
LATEST FOREIGN KEY ERROR
------------------------
2024-04-02 10:36:39 0x7f36088ff640 Transaction:
TRANSACTION 7199599266, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
6 lock struct(s), heap size 1128, 3 row lock(s), undo log entries 1
MariaDB thread id 228555, OS thread handle 139870048613952, query id 28453893 Write_rows_log_event::write_row(-1) on table `alerts`
insert into alerts (alertid,actionid,eventid,userid,clock,mediatypeid,sendto,subject,message,status,error,esc_step,alerttype,acknowledgeid,parameters) values (203687,4,471733,3,1712044003,1,'xxx@fromdual.com','Zabbix server - High: Too many processes on Zabbix server','Trigger: Too many processes on Zabbix server
Trigger status: PROBLEM
Trigger severity: High
Trigger URL:

Item values: 309

1. Number of processes (Zabbix server:proc.num[]): 309',3,'',1,0,null,'{}')
Foreign key constraint fails for table `zabbix`.`alerts`:
,
 CONSTRAINT `c_alerts_2` FOREIGN KEY (`eventid`) REFERENCES `events` (`eventid`) ON DELETE CASCADE in parent table, in index alerts_3 tuple:
DATA TUPLE: 2 fields;
 ...

But in parent table `zabbix`.`events`, in index PRIMARY,
the closest match we can find is record:
PHYSICAL RECORD: n_fields 12; compact format; info bits 0
 ...
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="literaturesources"&gt;Literature/Sources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/parallel-replication/" target="_blank"&gt;Parallel Replication&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Building MariaDB Server from the sources</title><link>https://www.fromdual.com/blog/building-mariadb-server-from-the-sources/</link><pubDate>Fri, 05 Apr 2024 08:47:13 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/building-mariadb-server-from-the-sources/</guid><description>&lt;p&gt;Recently I had to test a new MariaDB feature that was developed at our request (&lt;a href="https://jira.mariadb.org/browse/MDEV-33782" target="_blank"&gt;MDEV-33782&lt;/a&gt;). To test this feature I had to build the MariaDB server myself from source, which I have not done for a long time. So a new challenge, especially with &lt;code&gt;CMake&lt;/code&gt;&amp;hellip;&lt;/p&gt;
&lt;p&gt;I followed the MariaDB documentation &lt;a href="https://mariadb.com/kb/en/get-build-and-test-latest-mariadb-the-lazy-way/" target="_blank"&gt;Get, Build and Test Latest MariaDB the Lazy Way&lt;/a&gt; to build the server.&lt;/p&gt;
&lt;p&gt;On Ubuntu 22.04 it did not work for me, for reasons unknown to me. So I cloned an Ubuntu 23.04 (Lunar Lobster) LXC container and built the MariaDB server in it.&lt;/p&gt;
&lt;p&gt;To make the whole thing work, however, the package sources had to be added to the file &lt;code&gt;/etc/apt/sources.list&lt;/code&gt; in the container first:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;deb-src http://de.archive.ubuntu.com/ubuntu lunar main restricted universe multiverse
deb-src http://de.archive.ubuntu.com/ubuntu lunar-updates main restricted universe multiverse
deb-src http://de.archive.ubuntu.com/ubuntu lunar-security main restricted universe multiverse
deb-src http://de.archive.ubuntu.com/ubuntu lunar-backports main restricted universe multiverse
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we proceeded according to the instructions:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; apt install build-essential bison
shell&amp;gt; apt build-dep mariadb-server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The corresponding branch was cloned:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; # git clone https://github.com/andremralves/server.git mariadb-MDEV-33782
shell&amp;gt; # git branch --all
shell&amp;gt; git clone --branch MDEV-33782 --single-branch https://github.com/andremralves/server.git mariadb-MDEV-33782
shell&amp;gt; cd mariadb-MDEV-33782
shell&amp;gt; # git checkout 11.5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then the server was build. This took about 20 minutes on my old machine. &lt;code&gt;CMake&lt;/code&gt; still ran into an error, which was solved by installing the corresponding package (&lt;a href="https://jira.mariadb.org/browse/MDEV-33815" target="_blank"&gt;MDEV-33815&lt;/a&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; apt install libgnutls28-dev
shell&amp;gt; cmake . -DBUILD_CONFIG=mysql_release &amp;amp;&amp;amp; make -j8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The tests were executed:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; cd mysql-test
shell&amp;gt; ./mtr rpl.rpl_create_drop_event
Logging: ./mtr rpl.rpl_create_drop_event
VS config:
vardir: /root/mariadb-MDEV-33782/mysql-test/var
Checking leftover processes...
Removing old var directory...
Creating var directory '/root/mariadb-MDEV-33782/mysql-test/var'...
Checking supported features...
MariaDB Version 11.5.0-MariaDB
 - SSL connections supported
 - binaries built with wsrep patch
Collecting tests...
Installing system database...

==============================================================================

TEST RESULT TIME (ms) or COMMENT
--------------------------------------------------------------------------

worker[01] Using MTR_BUILD_THREAD 300, with reserved ports 16000..16019
worker[01] mysql-test-run: WARNING: running this script as _root_ will cause some tests to be skipped
rpl.rpl_create_drop_event 'mix' [ pass ] 522
rpl.rpl_create_drop_event 'row' [ pass ] 525
rpl.rpl_create_drop_event 'stmt' [ pass ] 525
--------------------------------------------------------------------------
The servers were restarted 2 times
Spent 1.572 of 14 seconds executing testcases

Completed: All 3 tests were successful.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then a &lt;a href="https://mariadb.com/kb/en/creating-the-mariadb-binary-tarball/" target="_blank"&gt;binary tarball was build&lt;/a&gt; for further testing.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; make package
Run CPack packaging tool...
CPack: Create package using TGZ
CPack: Install projects
CPack: - Run preinstall target for: MariaDB
CPack: - Install project: MariaDB []
CPack: Create package
CPack: - package: /root/mariadb-MDEV-33782/mariadb-11.5.0-linux-x86_64.tar.gz generated.
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>MaxScale configuration synchronisation</title><link>https://www.fromdual.com/blog/maxscale-configurations-synchronisation/</link><pubDate>Thu, 04 Apr 2024 09:53:46 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/maxscale-configurations-synchronisation/</guid><description>&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/maxscale-configurations-synchronisation/#overview"&gt;Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/maxscale-configurations-synchronisation/#preparations"&gt;Preparations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/maxscale-configurations-synchronisation/#activate-configuration-synchronization"&gt;Activate MaxScale configuration synchronisation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/maxscale-configurations-synchronisation/#change-parameter"&gt;Change MaxScale parameters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/maxscale-configurations-synchronisation/#add-new-slave"&gt;Add new slave and make MaxScale known&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/maxscale-configurations-synchronisation/#remove-old-slave"&gt;Remove old slave and make MaxScale known&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/maxscale-configurations-synchronisation/#how-is-configuration-synchronized"&gt;How is the configuration synchronised?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/maxscale-configurations-synchronisation/#what-happens-on-conflict"&gt;What happens in the event of a conflict?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/maxscale-configurations-synchronisation/#tests"&gt;Tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/maxscale-configurations-synchronisation/#deactivate-configuration-synchronization"&gt;Deactivating MaxScale configuration synchronisation again&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/maxscale-configurations-synchronisation/#literature"&gt;Literature/sources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;A feature that I recently discovered while browsing is the MaxScale configuration synchronisation functionality.&lt;/p&gt;
&lt;p&gt;This is not primarily about a MariaDB replication cluster or a MariaDB Galera cluster, but about a cluster consisting of two or more MaxScale nodes. Or more precisely, the exchange of the configuration between these MaxScale nodes.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.fromdual.com/sites/default/files/maxscale_config_sync.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;Pon Suresh Pandian has already written a &lt;a href="https://mariadb.com/resources/blog/mariadb-maxscale-6-0-native-clustering/" target="_blank"&gt;blog article&lt;/a&gt; about this feature in 2022, which is even more detailed than this post here.&lt;/p&gt;
&lt;h2 id="preparations"&gt;Preparations&lt;/h2&gt;
&lt;p&gt;An &lt;a href="https://linuxcontainers.org/incus/" target="_blank"&gt;Incus container&lt;/a&gt; environment was prepared, consisting of 3 database containers (deb12-n1 (10.139.158.33), deb12-n2 (10.139.158.178), deb12-n3 (10.139.158.39)) and 2 MaxScale containers (deb12-mxs1 (10.139.158.66), deb12-mxs2 (10.139.158.174)). The database version is a MariaDB 10.11.6 from the Debian repository and MaxScale was &lt;a href="https://mariadb.com/downloads/community/maxscale/" target="_blank"&gt;downloaded&lt;/a&gt; in version 22.08.5 from the MariaDB plc website.&lt;/p&gt;
&lt;p&gt;The database configuration looks similar for all 3 nodes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#
# /etc/mysql/mariadb.conf.d/99-fromdual.cnf
#

[server]

server_id = 1
log_bin = deb12-n1-binlog
binlog_format = row
bind_address = *
proxy_protocol_networks = ::1, 10.139.158.0/24, localhost
gtid_strict_mode = on
log_slave_updates = on
skip_name_resolve = on
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The MaxScale nodes were built as described in the article &lt;a href="https://www.fromdual.com/sharding-with-mariadb-maxscale"&gt;Sharding with MariaDB MaxScale&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;maxscale_admin&lt;/code&gt; user has exactly the same rights as described there, the &lt;code&gt;maxscale_monitor&lt;/code&gt; user has the following rights:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RELOAD, SUPER, REPLICATION SLAVE, READ_ONLY ADMIN
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See also here: &lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-monitor/#required-grants" target="_blank"&gt;Required Grants&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The MaxScale start configuration looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#
# /etc/maxscale.cnf
#

[maxscale]
threads = auto
admin_gui = false

[deb12-n1]
type = server
address = 10.139.158.33
port = 3306
proxy_protocol = true

[deb12-n2]
type = server
address = 10.139.158.178
port = 3306
proxy_protocol = true

[Replication-Monitor]
type = monitor
module = mariadbmon
servers = deb12-n1,deb12-n2
user = maxscale_monitor
password = secret
monitor_interval = 500ms
auto_failover = true
auto_rejoin = true
enforce_read_only_slaves = true
replication_user = replication
replication_password = secret
cooperative_monitoring_locks = majority_of_running

[WriteListener]
type = listener
service = WriteService
port = 3306

[WriteService]
type = service
router = readwritesplit
servers = deb12-n1,deb12-n2
user = maxscale_admin
password = secret
transaction_replay = true
transaction_replay_timeout = 30s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: The configuration should look the same on all MaxScale nodes!&lt;/p&gt;
&lt;p&gt;And then a few more checks were done to be sure that everything is correct:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl list listeners
┌───────────────┬──────┬──────┬─────────┬──────────────┐
│ Name │ Port │ Host │ State │ Service │
├───────────────┼──────┼──────┼─────────┼──────────────┤
│ WriteListener │ 3306 │ :: │ Running │ WriteService │
└───────────────┴──────┴──────┴─────────┴──────────────┘

shell&amp;gt; maxctrl list services
┌──────────────┬────────────────┬─────────────┬───────────────────┬────────────────────┐
│ Service │ Router │ Connections │ Total Connections │ Targets │
├──────────────┼────────────────┼─────────────┼───────────────────┼────────────────────┤
│ WriteService │ readwritesplit │ 0 │ 0 │ deb12-n1, deb12-n2 │
└──────────────┴────────────────┴─────────────┴───────────────────┴────────────────────┘

shell&amp;gt; maxctrl list servers
┌──────────┬────────────────┬──────┬─────────────┬─────────────────┬────────┬─────────────────────┐
│ Server │ Address │ Port │ Connections │ State │ GTID │ Monitor │
├──────────┼────────────────┼──────┼─────────────┼─────────────────┼────────┼─────────────────────┤
│ deb12-n1 │ 10.139.158.33 │ 3306 │ 0 │ Master, Running │ 0-1-19 │ Replication-Monitor │
├──────────┼────────────────┼──────┼─────────────┼─────────────────┼────────┼─────────────────────┤
│ deb12-n2 │ 10.139.158.178 │ 3306 │ 0 │ Slave, Running │ 0-1-19 │ Replication-Monitor │
└──────────┴────────────────┴──────┴─────────────┴─────────────────┴────────┴─────────────────────┘

SQL&amp;gt; SELECT @@hostname, test.* FROM test.test;
+------------+----+-----------+---------------------+
| @@hostname | id | data | ts |
+------------+----+-----------+---------------------+
| deb12-n2 | 1 | Some data | 2024-03-26 09:40:21 |
+------------+----+-----------+---------------------+

SQL&amp;gt; SELECT @@hostname, test.* FROM test.test FOR UPDATE;
+------------+----+-----------+---------------------+
| @@hostname | id | data | ts |
+------------+----+-----------+---------------------+
| deb12-n1 | 1 | Some data | 2024-03-26 09:40:21 |
+------------+----+-----------+---------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And another test whether MaxScale really executes the failover correctly:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; systemctl stop mariadb
2024-03-26 16:27:05 error : Monitor was unable to connect to server deb12-n2[10.139.158.178:3306] : 'Can't connect to server on '10.139.158.178' (115)'
2024-03-26 16:27:05 notice : Server changed state: deb12-n2[10.139.158.178:3306]: master_down. [Master, Running]→[Down]
2024-03-26 16:27:05 warning: [mariadbmon] Primary has failed. If primary does not return in 4 monitor tick(s), failover begins.
2024-03-26 16:27:07 notice : [mariadbmon] Selecting a server to promote and replace 'deb12-n2'. Candidates are: 'deb12-n1'.
2024-03-26 16:27:07 notice : [mariadbmon] Selected 'deb12-n1'.
2024-03-26 16:27:07 notice : [mariadbmon] Performing automatic failover to replace failed primary 'deb12-n2'.
2024-03-26 16:27:07 notice : [mariadbmon] Failover 'deb12-n2'→'deb12-n1' performed.
2024-03-26 16:27:07 notice : Server changed state: deb12-n1[10.139.158.33:3306]: new_master. [Slave, Running]→[Master, Running]

shell&amp;gt; systemctl start mariadb
2024-03-26 16:28:03 notice : Server changed state: deb12-n2[10.139.158.178:3306]: server_up. [Down]→[Running]
2024-03-26 16:28:03 notice : [mariadbmon] Directing standalone server 'deb12-n2' to replicate from 'deb12-n1'.
2024-03-26 16:28:03 notice : [mariadbmon] Replica connection from deb12-n2 to [10.139.158.33]:3306 created and started.
2024-03-26 16:28:03 notice : [mariadbmon] 1 server(s) redirected or rejoined the cluster.
2024-03-26 16:28:03 notice : Server changed state: deb12-n2[10.139.158.178:3306]: new_slave. [Running]→[Slave, Running]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which MaxScale node is currently responsible for monitoring and failover (&lt;code&gt;cooperatve_monitoring&lt;/code&gt;) can be determined as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl show monitor Replication-Monitor | grep -e 'Diagnostics' -e '&amp;quot;primary&amp;quot;' -e 'lock_held' | uniq
│ Monitor Diagnostics │ { │
│ │ &amp;quot;primary&amp;quot;: true, │
│ │ &amp;quot;lock_held&amp;quot;: true, │
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It should be ensured that everything works properly up to this point. Otherwise there is no real point in the next steps.&lt;/p&gt;
&lt;h2 id="activate-maxscale-configuration-synchronisation"&gt;Activate MaxScale configuration synchronisation&lt;/h2&gt;
&lt;p&gt;A separate database user with the following rights is required for configuration synchronisation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; CREATE USER 'maxscale_confsync'@'%' IDENTIFIED BY 'secret';
SQL&amp;gt; GRANT SELECT, INSERT, UPDATE, CREATE ON `mysql`.`maxscale_config` TO maxscale_confsync@'%';
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MaxScale must then be configured accordingly (on both MaxScale nodes) so that configuration synchronisation is activated. This configuration takes place in the global MaxScale section:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#
# /etc/maxscale.cnf
#

[maxscale]
config_sync_cluster = Replication-Monitor
config_sync_user = maxscale_confsync
config_sync_password = secret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The MaxScale nodes are then restarted:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; systemctl restart maxscale
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MaxScale configuration synchronisation can also be activated and deactivated dynamically:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl show maxscale | grep config_sync
│ │ &amp;quot;config_sync_cluster&amp;quot;: null, │
│ │ &amp;quot;config_sync_db&amp;quot;: &amp;quot;mysql&amp;quot;, │
│ │ &amp;quot;config_sync_interval&amp;quot;: &amp;quot;5000ms&amp;quot;, │
│ │ &amp;quot;config_sync_password&amp;quot;: null, │
│ │ &amp;quot;config_sync_timeout&amp;quot;: &amp;quot;10000ms&amp;quot;, │
│ │ &amp;quot;config_sync_user&amp;quot;: null, │
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here it is important to keep to the correct order of the 3 commands, otherwise there will be an error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; MAXCTRL_WARNINGS=0 maxctrl alter maxscale config_sync_user='maxscale_confsync'
shell&amp;gt; MAXCTRL_WARNINGS=0 maxctrl alter maxscale config_sync_password='secret'
shell&amp;gt; MAXCTRL_WARNINGS=0 maxctrl alter maxscale config_sync_cluster='Replication-Monitor'
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="change-maxscale-parameters"&gt;Change MaxScale parameters&lt;/h2&gt;
&lt;p&gt;As a first test, we have focussed on the MaxScale monitor variable &lt;code&gt;monitor_interval&lt;/code&gt;, which in this case is even different on both MaxScale nodes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl show monitor Replication-Monitor | grep monitor_interval
│ │ &amp;quot;monitor_interval&amp;quot;: &amp;quot;750ms&amp;quot;,

shell&amp;gt; maxctrl show monitor Replication-Monitor | grep monitor_interval
│ │ &amp;quot;monitor_interval&amp;quot;: &amp;quot;1000ms&amp;quot;,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The variable can now be set on a MaxScale node with the &lt;code&gt;alter monitor&lt;/code&gt; command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; MAXCTRL_WARNINGS=0 maxctrl alter monitor Replication-Monitor monitor_interval=500ms
OK
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which can be seen in the MaxScale error log:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2024-03-26 14:09:16 notice : (ConfigManager); Updating to configuration version 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the other hand, the value should be propagated to the second MaxScale node within 5 seconds (&lt;code&gt;config_sync_interval&lt;/code&gt;), which can be checked with the above command.&lt;/p&gt;
&lt;h2 id="add-new-slave-and-make-maxscale-known"&gt;Add new slave and make MaxScale known&lt;/h2&gt;
&lt;p&gt;A new slave (deb12-n3) is first created and added to the MariaDB replication cluster by hand. The slave is then made known to a MaxScale node:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl create server deb12-n3 10.139.158.39

shell&amp;gt; MAXCTRL_WARNINGS=0 maxctrl link monitor Replication-Monitor deb12-n3
OK

shell&amp;gt; MAXCTRL_WARNINGS=0 maxctrl link service WriteService deb12-n3
OK

shell&amp;gt; maxctrl list servers
┌──────────┬────────────────┬──────┬─────────────┬─────────────────┬────────────┬─────────────────────┐
│ Server │ Address │ Port │ Connections │ State │ GTID │ Monitor │
├──────────┼────────────────┼──────┼─────────────┼─────────────────┼────────────┼─────────────────────┤
│ deb12-n1 │ 10.139.158.33 │ 3306 │ 3 │ Slave, Running │ 0-2-479618 │ Replication-Monitor │
├──────────┼────────────────┼──────┼─────────────┼─────────────────┼────────────┼─────────────────────┤
│ deb12-n2 │ 10.139.158.178 │ 3306 │ 3 │ Master, Running │ 0-2-479618 │ Replication-Monitor │
├──────────┼────────────────┼──────┼─────────────┼─────────────────┼────────────┼─────────────────────┤
│ deb12-n3 │ 10.139.158.39 │ 3306 │ 1 │ Slave, Running │ 0-2-479618 │ Replication-Monitor │
└──────────┴────────────────┴──────┴─────────────┴─────────────────┴────────────┴─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="remove-old-slave-and-make-maxscale-known"&gt;Remove old slave and make MaxScale known&lt;/h2&gt;
&lt;p&gt;Before a slave can be deleted, it should be removed from the replication cluster for a MaxScale node:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl destroy server deb12-n1 --force
OK

shell&amp;gt; maxctrl list servers
┌──────────┬────────────────┬──────┬─────────────┬─────────────────┬────────────┬─────────────────────┐
│ Server │ Address │ Port │ Connections │ State │ GTID │ Monitor │
├──────────┼────────────────┼──────┼─────────────┼─────────────────┼────────────┼─────────────────────┤
│ deb12-n2 │ 10.139.158.178 │ 3306 │ 3 │ Master, Running │ 0-2-493034 │ Replication-Monitor │
├──────────┼────────────────┼──────┼─────────────┼─────────────────┼────────────┼─────────────────────┤
│ deb12-n3 │ 10.139.158.39 │ 3306 │ 1 │ Slave, Running │ 0-2-493032 │ Replication-Monitor │
└──────────┴────────────────┴──────┴─────────────┴─────────────────┴────────────┴─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The slave can then be removed.&lt;/p&gt;
&lt;h2 id="how-is-the-configuration-synchronised"&gt;How is the configuration synchronised?&lt;/h2&gt;
&lt;p&gt;The configuration of the two MaxScale nodes is synchronised via the database, which I personally consider to be an unfortunate design decision, as a configuration change could potentially cause chaos if the master breaks or network problems occur between the database nodes&amp;hellip;&lt;/p&gt;
&lt;p&gt;The configuration is stored in the table &lt;code&gt;mysql.maxscale_config&lt;/code&gt;, which looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CREATE TABLE `maxscale_config` (
 `cluster` varchar(256) NOT NULL,
 `version` bigint(20) NOT NULL,
 `config` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`config`)),
 `origin` varchar(254) NOT NULL,
 `nodes` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`nodes`)),
 PRIMARY KEY (`cluster`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This table has approximately the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SELECT cluster, version, CONCAT(SUBSTR(config, 1, 32), ' ... ', SUBSTR(config, -32)) AS config , origin, nodes FROM mysql.maxscale_config;
+---------------------+---------+-----------------------------------------------------------------------+------------+------------------------------------------+
| cluster | version | config | origin | nodes |
+---------------------+---------+-----------------------------------------------------------------------+------------+------------------------------------------+
| Replication-Monitor | 2 | {&amp;quot;config&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;deb12-n1&amp;quot;,&amp;quot;typ ... ter_name&amp;quot;:&amp;quot;Replication-Monitor&amp;quot;} | deb12-mxs1 | {&amp;quot;deb12-mxs1&amp;quot;: &amp;quot;OK&amp;quot;, &amp;quot;deb12-mxs2&amp;quot;: &amp;quot;OK&amp;quot;} |
+---------------------+---------+-----------------------------------------------------------------------+------------+------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A local copy is available on each node for security reasons:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; cut -b-32 /var/lib/maxscale/maxscale-config.json
{&amp;quot;config&amp;quot;:[{&amp;quot;id&amp;quot;:&amp;quot;deb12-n2&amp;quot;,&amp;quot;typ
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="what-happens-in-the-event-of-a-conflict"&gt;What happens in the event of a conflict?&lt;/h2&gt;
&lt;p&gt;See also: &lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#error-handling-in-configuration-synchronization" target="_blank"&gt;Error Handling in Configuration Synchronization&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If the configuration is changed simultaneously (within &lt;code&gt;config_sync_interval&lt;/code&gt;?) on two different MaxScale nodes, we receive the following error message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Error: Server at http://127.0.0.1:8989 responded with 400 Bad Request to `PATCH monitors/Replication-Monitor`
{
 &amp;quot;errors&amp;quot;: [
 {
 &amp;quot;detail&amp;quot;: &amp;quot;Cannot start configuration change: Configuration conflict detected: version stored in the cluster (3) is not the same as the local version (2), MaxScale is out of sync.&amp;quot;
 }
 ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following command may help to recognise the problem in the event of major faults:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl show maxscale | grep -A9 'Config Sync'
│ Config Sync │ { │
│ │ &amp;quot;checksum&amp;quot;: &amp;quot;0052fe6f775168bf00778abbe37775f6f642adc7&amp;quot;, │
│ │ &amp;quot;nodes&amp;quot;: { │
│ │ &amp;quot;deb12-mxs1&amp;quot;: &amp;quot;OK&amp;quot;, │
│ │ &amp;quot;deb12-mxs2&amp;quot;: &amp;quot;OK&amp;quot; │
│ │ }, │
│ │ &amp;quot;origin&amp;quot;: &amp;quot;deb12-mxs2&amp;quot;, │
│ │ &amp;quot;status&amp;quot;: &amp;quot;OK&amp;quot;, │
│ │ &amp;quot;version&amp;quot;: 3 │
│ │ } │
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="tests"&gt;Tests&lt;/h2&gt;
&lt;p&gt;All tests were also carried out under load. The following tests ran in parallel:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;insert_test.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;insert_test.sh&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mixed_test.php&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;while [ true ] ; do mariadb -s --user=app --host=10.139.158.174 --port=3306 --password=secret --execute='SELECT @@hostname, COUNT(*) FROM test.test GROUP BY @@hostname' ; sleep 0.5 ; done&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;while [ true ] ; do mariadb -s --user=app --host=10.139.158.174 --port=3306 --password=secret --execute='SELECT @@hostname, COUNT(*) FROM test.test GROUP BY @@hostname FOR UPDATE' ; sleep 0.5 ; done&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All tests have run flawlessly and without problems with all manipulations.&lt;/p&gt;
&lt;h2 id="deactivate-maxscale-configuration-synchronisation-again"&gt;Deactivate MaxScale configuration synchronisation again&lt;/h2&gt;
&lt;p&gt;Execute the following command on both MaxScale nodes to end configuration synchronisation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; MAXCTRL_WARNINGS=0 maxctrl alter maxscale config_sync_cluster=''
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="literaturesources"&gt;Literature/sources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#config_sync_cluster" target="_blank"&gt;MaxScale globale Konfigurationsvariable: config_sync_cluster&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#configuration-synchronization" target="_blank"&gt;MaxScale Configuration Synchronization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/resources/blog/mariadb-maxscale-6-0-native-clustering/" target="_blank"&gt;Pon Suresh Pandian, MariaDB, 24. August 2022: MariaDB MaxScale 6.0 Native Clustering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jira.mariadb.org/browse/MXS-4144" target="_blank"&gt;Where to get maxscale 6 mysql.maxscale_config table source sql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-setting-up-mariadb-maxscale/" target="_blank"&gt;Setting up MariaDB MaxScale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-configuring-the-mariadb-monitor/" target="_blank"&gt;Configuring the MariaDB Monitor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/mariadb-maxscale-load-balancer-with-master-master-replication"&gt;MariaDB MaxScale Load Balancer with Master/Master Replication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-monitor/#configuration" target="_blank"&gt;MariaDB Monitor - Configuration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Sharding with MariaDB MaxScale</title><link>https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/</link><pubDate>Tue, 19 Mar 2024 17:02:58 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/</guid><description>&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#overview"&gt;Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#preparation"&gt;Preparation of the shards (MariaDB database instances)&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#creating-test-data"&gt;Create test data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#creating-roles-and-users"&gt;Creating roles and users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#maxscale-monitor-user"&gt;MaxScale Monitor User&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#mascale-admin-user"&gt;MaxScale Admin User&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#create-application-role-and-accounts"&gt;Create application role and accounts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#proxy-protocol"&gt;Proxy protocol&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#maxscale-schema-router-configuration"&gt;MaxScale SchemaRouter configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#starting-and-stopping-maxscale"&gt;Starting and stopping the MaxScale Load Balancer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#application-tests"&gt;Application tests&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#simple-applicationt-test"&gt;Simple application tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#new-command-show-shards"&gt;New command show shards&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#general-tests"&gt;More general test&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#less-simple-tests"&gt;Less simple tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#more-complex-application-tests"&gt;More complex application tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#cross-shard-tests"&gt;Cross-shard tests&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#operation-of-a-sharding-system"&gt;Operation of a MaxScale sharding system&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#do-on-all-shards"&gt;Do-on-all-shards&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#invalidate-database-map-cache"&gt;Invalidating the database map cache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#changing-schema-router-variables-dynamically"&gt;How to change SchemaRouter variables dynamically?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#adding-and-removing-a-tenant"&gt;Adding and removing a tenant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#moving-a-tenant"&gt;Moving a tenant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#adding-or-removing-a-shard"&gt;Adding or removing a shard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#adapting-configuration-files"&gt;Customising the configuration files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#maintenance-work-on-a-shard"&gt;Maintenance work on the shard&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#observation-of-a-sharding-system"&gt;Observation / monitoring of a MariaDB MaxScale sharding system&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/sharding-with-mariadb-maxscale/#literature"&gt;Literature / Sources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;This feature should more or less work with MariaDB MaxScale 6.x.y, 22.08.x, 23.02.x, 23.08.x and 24.02.x. We have tested it with the latest MaxScale version 23.08.05, as we encountered problems with an older version (&lt;a href="https://jira.mariadb.org/browse/MXS-5026" target="_blank"&gt;MXS-5026&lt;/a&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxscale --version
MaxScale 23.08.5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We used MariaDB 10.11 as the database backend (shards).&lt;/p&gt;
&lt;p&gt;Less than approx. 2% of all MariaDB installations known to us are what we technically understand by multi-tenant systems (each customer in its own database (also called a schema)).&lt;/p&gt;
&lt;p&gt;This MariaDB MaxScale feature is therefore used relatively rarely and there is an increased risk of encountering bugs that no-one has come across before!&lt;/p&gt;
&lt;p&gt;This feature is called &lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-schemarouter/" target="_blank"&gt;SchemaRouter&lt;/a&gt; at MariadDB MaxScale and is still declared as beta quality (&lt;a href="https://jira.mariadb.org/browse/MXS-5025" target="_blank"&gt;MXS-5025&lt;/a&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;maxctrl&amp;gt; show module schemarouter
┌─────────────┬────────────────────────────────────────────────┐
│ Module │ schemarouter │
├─────────────┼────────────────────────────────────────────────┤
│ Type │ Router │
├─────────────┼────────────────────────────────────────────────┤
│ Version │ V1.0.0 │
├─────────────┼────────────────────────────────────────────────┤
│ Maturity │ Beta │
├─────────────┼────────────────────────────────────────────────┤
│ Description │ A database sharding router for simple sharding │
├─────────────┼────────────────────────────────────────────────┤
│ ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The target topology should look like this: Each customer (client, tenant) is located in its own database (= schema). The databases are distributed across several MariaDB instances (shards). So that the application can access the database transparently, a pair of MaxScale load balancers is connected in front of it, which knows where the customer is located and forwards the traffic to the shard accordingly. To ensure that the MaxScale load balancers are designed for high availability, a virtual IP (VIP) is connected upstream, e.g. using Keepalived. If this is still too simple for you, you can design each individual shard as a master/slave or Galera cluster construct&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.fromdual.com/sites/default/files/sharding_0.png" alt=""&gt;&lt;/p&gt;
&lt;h2 id="preparation-of-the-shards-mariadb-database-instances"&gt;Preparation of the shards (MariaDB database instances)&lt;/h2&gt;
&lt;p&gt;The first problem we had with this PoC was with the &lt;code&gt;test&lt;/code&gt; database. By deleting the &lt;code&gt;test&lt;/code&gt; database on all shards, the problem disappeared. Alternatively, you can run &lt;code&gt;mariadb-secure-installation&lt;/code&gt;, which you should do on production systems anyway, or you can use the MaxScale configuration parameters: &lt;code&gt;ignore_tables&lt;/code&gt; or &lt;code&gt;ignore_tables_regex&lt;/code&gt; to allow the same tables in different shards (&lt;a href="https://jira.mariadb.org/browse/MXS-5027" target="_blank"&gt;MXS-5027&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;See also: &lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-schemarouter/#router-parameters" target="_blank"&gt;MaxScale Router Parameters&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="create-test-data"&gt;Create test data&lt;/h2&gt;
&lt;p&gt;So that we have something to play with, we have created test data:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-- On shard 1: 2 customers

SQL&amp;gt; CREATE DATABASE customer_0010;
SQL&amp;gt; CREATE TABLE customer_0010.address (id INT UNSIGNED, name VARCHAR(255));
SQL&amp;gt; CREATE TABLE customer_0010.sales (id INT UNSIGNED, product VARCHAR(255), sales TINYINT, amount DECIMAL(6, 2), total_amount DECIMAL(6, 2));
SQL&amp;gt; INSERT INTO customer_0010.address VALUES (1, 'Customer 10 GmbH');
SQL&amp;gt; INSERT INTO customer_0010.sales VALUES (1, 'Apples', 5, 1.2, 6), (2, 'Pears', 2, 0.9, 1.8), (3, 'Bread', 1, 2.5, 2.5);

SQL&amp;gt; CREATE DATABASE customer_0011;
SQL&amp;gt; CREATE TABLE customer_0011.address (id INT UNSIGNED, name VARCHAR(255));
SQL&amp;gt; CREATE TABLE customer_0011.sales (id INT UNSIGNED, product VARCHAR(255), sales TINYINT, amount DECIMAL(6, 2), total_amount DECIMAL(6, 2));
SQL&amp;gt; INSERT INTO customer_0011.address VALUES (1, 'Customer 11 SE');
SQL&amp;gt; INSERT INTO customer_0011.sales VALUES (1, 'Oranges', 2, 1.7, 3.4), (2, 'Salad', 5, 1.2, 6);

-- On shard 2: 3 customers

SQL&amp;gt; CREATE DATABASE customer_0020;
SQL&amp;gt; CREATE TABLE customer_0020.address (id INT UNSIGNED, name VARCHAR(255));
SQL&amp;gt; CREATE TABLE customer_0020.sales (id INT UNSIGNED, product VARCHAR(255), sales TINYINT, amount DECIMAL(6, 2), total_amount DECIMAL(6, 2));
SQL&amp;gt; INSERT INTO customer_0020.address VALUES (1, 'Customer 20 AG');
SQL&amp;gt; INSERT INTO customer_0020.sales VALUES (1, 'Oranges', 2, 1.7, 3.4), (2, 'Salad', 5, 1.2, 6);

SQL&amp;gt; CREATE DATABASE customer_0021;
SQL&amp;gt; CREATE TABLE customer_0021.address (id INT UNSIGNED, name VARCHAR(255));
SQL&amp;gt; CREATE TABLE customer_0021.sales (id INT UNSIGNED, product VARCHAR(255), sales TINYINT, amount DECIMAL(6, 2), total_amount DECIMAL(6, 2));
SQL&amp;gt; INSERT INTO customer_0021.address VALUES (1, 'Customer 21 GmbH');
SQL&amp;gt; INSERT INTO customer_0021.sales VALUES (1, 'Oranges', 2, 1.7, 3.4), (2, 'Salad', 5, 1.2, 6);

SQL&amp;gt; CREATE DATABASE customer_0022;
SQL&amp;gt; CREATE TABLE customer_0022.address (id INT UNSIGNED, name VARCHAR(255));
SQL&amp;gt; CREATE TABLE customer_0022.sales (id INT UNSIGNED, product VARCHAR(255), sales TINYINT, amount DECIMAL(6, 2), total_amount DECIMAL(6, 2));
SQL&amp;gt; INSERT INTO customer_0022.address VALUES (1, 'Customer 22 Gebr.');
SQL&amp;gt; INSERT INTO customer_0022.sales VALUES (1, 'Oranges', 2, 1.7, 3.4), (2, 'Salad', 5, 1.2, 6);

-- On shard 3: 1 customer

SQL&amp;gt; CREATE DATABASE customer_0030;
SQL&amp;gt; CREATE TABLE customer_0030.address (id INT UNSIGNED, name VARCHAR(255));
SQL&amp;gt; CREATE TABLE customer_0030.sales (id INT UNSIGNED, product VARCHAR(255), sales TINYINT, amount DECIMAL(6, 2), total_amount DECIMAL(6, 2));
SQL&amp;gt; INSERT INTO customer_0030.address VALUES (1, 'Customer 30 GmbH');
SQL&amp;gt; INSERT INTO customer_0030.sales VALUES (1, 'Pickles', 2, 2.2, 4.4), (2, 'Salad', 1, 3.1, 3.1), (3, 'Pudding', 5, 2.2, 11.0), (4, 'Asparagus', 12, .3, 3.6);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="create-roles-and-users"&gt;Create roles and users&lt;/h2&gt;
&lt;p&gt;Since in a sharded system, in contrast to a Galera cluster for example, the individual database instances do not know anything about each other and do not communicate with each other, we have to create the roles and users or accounts individually on EACH shard.&lt;/p&gt;
&lt;p&gt;MariaDB MaxScale needs a user for the SchemaRouter service and the monitor (on each shard).&lt;/p&gt;
&lt;p&gt;As the name suggests, the monitor user is responsible for monitoring and the SchemaRouter service user is responsible for collecting the user account information from the sharding backends and forwarding the queries to the correct shard.&lt;/p&gt;
&lt;p&gt;Since a redundant system typically works with at least two MaxScale routers and we wanted to prevent the privileges of the accounts from diverging, we work with roles for both the MaxScale users and the application users.&lt;/p&gt;
&lt;h2 id="maxscale-monitor-user"&gt;MaxScale Monitor User&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; CREATE ROLE maxscale_monitor_role;

SQL&amp;gt; GRANT SELECT ON mysql.user TO 'maxscale_monitor_role';
SQL&amp;gt; GRANT REPLICATION CLIENT ON *.* TO 'maxscale_monitor_role';
SQL&amp;gt; GRANT SLAVE MONITOR ON *.* TO 'maxscale_monitor_role';
SQL&amp;gt; GRANT FILE ON *.* TO 'maxscale_monitor_role';
SQL&amp;gt; GRANT CONNECTION ADMIN ON *.* TO 'maxscale_monitor_role';

SQL&amp;gt; SHOW GRANTS FOR maxscale_monitor_role;
+-----------------------------------------------------------------------------------------------+
| Grants for maxscale_monitor_role |
+-----------------------------------------------------------------------------------------------+
| GRANT FILE, BINLOG MONITOR, CONNECTION ADMIN, SLAVE MONITOR ON *.* TO `maxscale_monitor_role` |
| GRANT SELECT ON `mysql`.`user` TO `maxscale_monitor_role` |
+-----------------------------------------------------------------------------------------------+

SQL&amp;gt; CREATE USER maxscale_monitor@'10.139.158.210' IDENTIFIED BY 'secret';
SQL&amp;gt; CREATE USER maxscale_monitor@'10.139.158.211' IDENTIFIED BY 'secret';

SQL&amp;gt; GRANT maxscale_monitor_role TO maxscale_monitor@'10.139.158.210';
SQL&amp;gt; GRANT maxscale_monitor_role TO maxscale_monitor@'10.139.158.211';

SQL&amp;gt; SET DEFAULT ROLE maxscale_monitor_role FOR maxscale_monitor@'10.139.158.210';
SQL&amp;gt; SET DEFAULT ROLE maxscale_monitor_role FOR maxscale_monitor@'10.139.158.211';

SQL&amp;gt; SELECT user, host, is_role, default_role FROM mysql.user WHERE user LIKE 'maxscale_monitor%';
+-----------------------+----------------+---------+-----------------------+
| User | Host | is_role | default_role |
+-----------------------+----------------+---------+-----------------------+
| maxscale_monitor_role | | Y | |
| maxscale_monitor | 10.139.158.210 | N | maxscale_monitor_role |
| maxscale_monitor | 10.139.158.211 | N | maxscale_monitor_role |
+-----------------------+----------------+---------+-----------------------+

SQL&amp;gt; SHOW GRANTS FOR maxscale_monitor@'10.139.158.211';
+------------------------------------------------------------------------------------------------------------------------------+
| Grants for maxscale_monitor@10.139.158.211 |
+------------------------------------------------------------------------------------------------------------------------------+
| GRANT `maxscale_monitor_role` TO `maxscale_monitor`@`10.139.158.211` |
| GRANT USAGE ON *.* TO `maxscale_monitor`@`10.139.158.211` IDENTIFIED BY PASSWORD '*14E65567ABDB5135D0CFD9A70B3032C179A49EE7' |
| SET DEFAULT ROLE `maxscale_monitor_role` FOR `maxscale_monitor`@`10.139.158.211` |
+------------------------------------------------------------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="maxscale-admin-user"&gt;MaxScale Admin User&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; CREATE ROLE maxscale_admin_role;

SQL&amp;gt; GRANT SHOW DATABASES ON *.* TO 'maxscale_admin_role';
SQL&amp;gt; GRANT SELECT ON mysql.user TO 'maxscale_admin_role';
SQL&amp;gt; GRANT SELECT ON mysql.db TO 'maxscale_admin_role';
SQL&amp;gt; GRANT SELECT ON mysql.tables_priv TO 'maxscale_admin_role';
SQL&amp;gt; GRANT SELECT ON mysql.columns_priv TO 'maxscale_admin_role';
SQL&amp;gt; GRANT SELECT ON mysql.proxies_priv TO 'maxscale_admin_role';
SQL&amp;gt; GRANT SELECT ON mysql.roles_mapping TO 'maxscale_admin_role';
SQL&amp;gt; GRANT SELECT ON mysql.procs_priv TO 'maxscale_admin_role';

SQL&amp;gt; SHOW GRANTS FOR maxscale_admin_role;
+------------------------------------------------------------------+
| Grants for maxscale_admin_role |
+------------------------------------------------------------------+
| GRANT USAGE ON *.* TO `maxscale_admin_role` |
| GRANT SELECT ON `mysql`.`user` TO `maxscale_admin_role` |
| GRANT SELECT ON `mysql`.`roles_mapping` TO `maxscale_admin_role` |
| GRANT SELECT ON `mysql`.`tables_priv` TO `maxscale_admin_role` |
| GRANT SELECT ON `mysql`.`procs_priv` TO `maxscale_admin_role` |
| GRANT SELECT ON `mysql`.`db` TO `maxscale_admin_role` |
| GRANT SELECT ON `mysql`.`columns_priv` TO `maxscale_admin_role` |
| GRANT SELECT ON `mysql`.`proxies_priv` TO `maxscale_admin_role` |
+------------------------------------------------------------------+

SQL&amp;gt; CREATE USER maxscale_admin@'10.139.158.210' IDENTIFIED BY 'secret';
SQL&amp;gt; CREATE USER maxscale_admin@'10.139.158.211' IDENTIFIED BY 'secret';

SQL&amp;gt; GRANT maxscale_admin_role TO maxscale_admin@'10.139.158.210';
SQL&amp;gt; GRANT maxscale_admin_role TO maxscale_admin@'10.139.158.211';

SQL&amp;gt; SET DEFAULT ROLE maxscale_admin_role FOR maxscale_admin@'10.139.158.210';
SQL&amp;gt; SET DEFAULT ROLE maxscale_admin_role FOR maxscale_admin@'10.139.158.211';

SQL&amp;gt; SELECT user, host, is_role, default_role FROM mysql.user WHERE user LIKE 'maxscale_admin%';
+---------------------+----------------+---------+---------------------+
| User | Host | is_role | default_role |
+---------------------+----------------+---------+---------------------+
| maxscale_admin_role | | Y | |
| maxscale_admin | 10.139.158.210 | N | maxscale_admin_role |
| maxscale_admin | 10.139.158.211 | N | maxscale_admin_role |
+---------------------+----------------+---------+---------------------+

SQL&amp;gt; SHOW GRANTS FOR maxscale_admin@'10.139.158.211';
+----------------------------------------------------------------------------------------------------------------------------+
| Grants for maxscale_admin@10.139.158.211 |
+----------------------------------------------------------------------------------------------------------------------------+
| GRANT `maxscale_admin_role` TO `maxscale_admin`@`10.139.158.211` |
| GRANT USAGE ON *.* TO `maxscale_admin`@`10.139.158.211` IDENTIFIED BY PASSWORD '*14E65567ABDB5135D0CFD9A70B3032C179A49EE7' |
| SET DEFAULT ROLE `maxscale_admin_role` FOR `maxscale_admin`@`10.139.158.211` |
+----------------------------------------------------------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See also: &lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-schemarouter/#configuration" target="_blank"&gt;SchemaRouter Configuration&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="create-application-role-and-accounts"&gt;Create application role and accounts&lt;/h2&gt;
&lt;p&gt;The application also requires a user, which we create here as on every shard as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; CREATE ROLE app_role;
SQL&amp;gt; GRANT SELECT, INSERT, UPDATE, DELETE ON `customer_%`.* TO 'app_role';
SQL&amp;gt; GRANT SHOW DATABASES ON *.* TO 'app_role';
SQL&amp;gt; GRANT CREATE, DROP, ALTER ON *.* TO 'app_role'; -- For creating new tenant databases

SQL&amp;gt; SHOW GRANTS FOR app_role;
+----------------------------------------------------------------------+
| Grants for app_role |
+----------------------------------------------------------------------+
| GRANT SHOW DATABASES ON *.* TO `app_role` |
| GRANT SELECT, INSERT, UPDATE, DELETE ON `customer_%`.* TO `app_role` |
+----------------------------------------------------------------------+

SQL&amp;gt; CREATE USER app@'10.139.158.%' IDENTIFIED BY 'secret';
SQL&amp;gt; GRANT app_role TO app@'10.139.158.%';
SQL&amp;gt; SET DEFAULT ROLE app_role FOR app@'10.139.158.%';

SQL&amp;gt; SELECT user, host, is_role, default_role FROM mysql.user WHERE user LIKE 'app%';
+----------+--------------+---------+--------------+
| User | Host | is_role | default_role |
+----------+--------------+---------+--------------+
| app_role | | Y | |
| app | 10.139.158.% | N | app_role |
+----------+--------------+---------+--------------+

SQL&amp;gt; SHOW GRANTS FOR app@'10.139.158.%';
+---------------------------------------------------------------------------------------------------------------+
| Grants for app@10.139.158.% |
+---------------------------------------------------------------------------------------------------------------+
| GRANT `app_role` TO `app`@`10.139.158.%` |
| GRANT USAGE ON *.* TO `app`@`10.139.158.%` IDENTIFIED BY PASSWORD '*14E65567ABDB5135D0CFD9A70B3032C179A49EE7' |
| SET DEFAULT ROLE `app_role` FOR `app`@`10.139.158.%` |
+---------------------------------------------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="proxy-protocol"&gt;Proxy protocol&lt;/h2&gt;
&lt;p&gt;Load balancers and proxies have the property that they exchange the IP addresses of the clients with their own IP addresses. On the one hand, this means that you can no longer see where the client originally came from in the database and, on the other hand, you can no longer assign access authorisations to users and IPs, as the IP of the load balancer is always checked.&lt;/p&gt;
&lt;p&gt;These two problems can be solved using the proxy protocol.&lt;/p&gt;
&lt;p&gt;To do this, both the database and the load balancer, in this case MaxScale, must have the proxy protocol activated.&lt;/p&gt;
&lt;p&gt;On the database side, the proxy protocol is activated as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#
# my.cnf
#

[mariadbd]

proxy_protocol_networks = ::1, 10.139.158.0/24, localhost
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and on the MaxScale side with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#
# /etc/maxscale.cnf
#

[shard]
type = server
proxy_protocol = true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can check the two settings with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SHOW GLOBAL VARIABLES LIKE 'proxy%';
+-------------------------+---------------------------------+
| Variable_name | Value |
+-------------------------+---------------------------------+
| proxy_protocol_networks | ::1, 10.139.158.0/24, localhost |
+-------------------------+---------------------------------+

shell&amp;gt; maxctrl show server shard1 | grep proxy
│ │ &amp;quot;proxy_protocol&amp;quot;: true, │
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt" target="_blank"&gt;The PROXY protocol, Versions 1 &amp;amp; 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-configuration-guide/#proxy_protocol" target="_blank"&gt;MariaDB MaxScale Configuration Guide - Proxy Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/proxy-protocol-support/" target="_blank"&gt;MariaDB Knowledge Base: Proxy Protocol Support&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="maxscale-schemarouter-configuration"&gt;MaxScale SchemaRouter configuration&lt;/h2&gt;
&lt;p&gt;Next, we prepare the MaxScale configuration for sharding. The file recommended by MariaDB is &lt;code&gt;/etc/maxscale.cnf&lt;/code&gt;. Whether it makes more sense to create a separate configuration file under &lt;code&gt;/etc/maxscale.cnf.d/&lt;/code&gt; or even to configure the entire MaxScale dynamically (&lt;code&gt;/var/lib/maxscale/maxscale.cnf.d/*.cnf&lt;/code&gt;) remains to be seen in the long term. See also warnings below. The configuration file for this sharding PoC looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#
# /etc/maxscale.cnf
#

[maxscale]
threads = auto
admin_gui = false

[shard1]
type = server
address = 10.139.158.1
port = 3363
proxy_protocol = true

[shard2]
type=server
address=10.139.158.1
port=3364
proxy_protocol = true

[shard3]
type = server
address = 10.139.158.1
port = 3365
proxy_protocol = true

[sharding monitor]
type = monitor
module = galeramon
servers = shard1,shard2,shard3
user = maxscale_monitor
password = secret
monitor_interval = 1s

[Sharded-Service-Listener]
type = listener
service = Sharded-Service
protocol = MariaDBClient
port = 3306

[Sharded-Service]
type = service
router = schemarouter
servers = shard1,shard2,shard3
user = maxscale_admin
password = secret
auth_all_servers = true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Recommendation of the MaxScale developer: &amp;ldquo;One workaround might be to actually use &lt;code&gt;galeramon&lt;/code&gt; to monitor the nodes instead of &lt;code&gt;mariadbmon&lt;/code&gt;.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="starting-and-stopping-the-maxscale-load-balancer"&gt;Starting and stopping the MaxScale Load Balancer&lt;/h2&gt;
&lt;p&gt;MaxScale is started and stopped as usual via SystemD:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; systemctl restart maxscale

shell&amp;gt; systemctl status maxscale
● maxscale.service - MariaDB MaxScale Database Proxy
 Loaded: loaded (/lib/systemd/system/maxscale.service; enabled; vendor preset: enabled)
 Drop-In: /run/systemd/system/service.d
 └─zzz-lxc-service.conf
 Active: active (running) since Tue 2024-02-27 09:52:57 UTC; 39s ago
 Process: 187 ExecStart=/usr/bin/maxscale (code=exited, status=0/SUCCESS)
 Main PID: 188 (maxscale)
 Tasks: 10 (limit: 18663)
 Memory: 4.6M
 CPU: 150ms
 CGroup: /system.slice/maxscale.service
 └─188 /usr/bin/maxscale

systemd[1]: Starting MariaDB MaxScale Database Proxy...
maxscale[188]: Module 'galeramon' loaded from '/usr/lib/x86_64-linux-gnu/maxscale/libgaleramon.so'.
maxscale[188]: Module 'schemarouter' loaded from '/usr/lib/x86_64-linux-gnu/maxscale/libschemarouter.so'.
maxscale[188]: Using up to 2.3GiB of memory for query classifier cache
systemd[1]: Started MariaDB MaxScale Database Proxy.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If there were errors or warnings, you can see them in the MaxScale error log:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; grep -v notice /var/log/maxscale/maxscale.log
2024-02-13 16:47:22 MariaDB MaxScale is shut down.
----------------------------------------------------


MariaDB MaxScale /var/log/maxscale/maxscale.log Tue Feb 13 16:47:22 2024
----------------------------------------------------------------------------
2024-02-27 09:52:56 warning: Discarding journal file '/var/lib/maxscale/Sharding-Monitor_journal.json'. File is for module 'mariadbmon'. Current module is 'galeramon'.
2024-02-27 09:52:56 warning: [galeramon] Invalid 'wsrep_local_index' on server 'shard1': 18446744073709551615
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="application-tests"&gt;Application tests&lt;/h2&gt;
&lt;h3 id="simple-application-tests"&gt;Simple application tests&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; mariadb --user=app --password=secret --host=10.139.158.211 --port=3306 --execute='show databases'
+--------------------+
| Database |
+--------------------+
| customer_0010 |
| customer_0011 |
| customer_0020 |
| customer_0021 |
| customer_0022 |
| customer_0030 |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="new-command-show-shards"&gt;New command &lt;code&gt;show shards&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; mariadb --user=app --password=secret --host=10.139.158.211 --port=3306 customer_0030 --execute='show shards' | grep customer_00.* | sort | column -t
customer_0010.address shard1
customer_0010.sales shard1
customer_0010. shard1
customer_0011.address shard1
customer_0011.sales shard1
customer_0011. shard1
customer_0020.address shard2
customer_0020.sales shard2
customer_0020. shard2
customer_0021.address shard2
customer_0021.sales shard2
customer_0021. shard2
customer_0022.address shard2
customer_0022.sales shard2
customer_0022. shard2
customer_0030.address shard3
customer_0030.sales shard3
customer_0030. shard3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;New databases are not displayed immediately, but only when the cached data has been updated (&lt;code&gt;refresh_interval&lt;/code&gt; (300s / 5 min)).&lt;/p&gt;
&lt;p&gt;See also: &lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-schemarouter/#custom-sql-commands" target="_blank"&gt;Custom SQL commands&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="more-general-test"&gt;More general test&lt;/h3&gt;
&lt;p&gt;As a reminder:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Shard&lt;/th&gt;
&lt;th&gt;Port&lt;/th&gt;
&lt;th&gt;Customer&lt;/th&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;#1&lt;/td&gt;
&lt;td&gt;3363&lt;/td&gt;
&lt;td&gt;customer_001&amp;lt;n&amp;gt;&lt;/td&gt;
&lt;td&gt;Running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#2&lt;/td&gt;
&lt;td&gt;3364&lt;/td&gt;
&lt;td&gt;customer_002&amp;lt;n&amp;gt;&lt;/td&gt;
&lt;td&gt;Running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#3&lt;/td&gt;
&lt;td&gt;3365&lt;/td&gt;
&lt;td&gt;customer_003&amp;lt;n&amp;gt;&lt;/td&gt;
&lt;td&gt;Running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#4&lt;/td&gt;
&lt;td&gt;3366&lt;/td&gt;
&lt;td&gt;customer_004&amp;lt;n&amp;gt;&lt;/td&gt;
&lt;td&gt;Running&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; mariadb --user=app --password=secret --host=10.139.158.211 --port=3306 --execute='SELECT @@port'
+--------+
| @@port |
+--------+
| 3363 |
+--------+
shell&amp;gt; mariadb --user=app --password=secret --host=10.139.158.211 --port=3306 --database=customer_0010 --execute='SELECT @@port'
+--------+
| @@port |
+--------+
| 3363 |
+--------+
shell&amp;gt; mariadb --user=app --password=secret --host=10.139.158.211 --port=3306 --database=customer_0020 --execute='SELECT @@port'
+--------+
| @@port |
+--------+
| 3364 |
+--------+
shell&amp;gt; mariadb --user=app --password=secret --host=10.139.158.211 --port=3306 --execute='use customer_0020; SELECT @@port'
+--------+
| @@port |
+--------+
| 3364 |
+--------+
shell&amp;gt; mariadb --user=app --password=secret --host=10.139.158.211 --port=3306 customer_0010 --execute='SELECT @@port'
+--------+
| @@port |
+--------+
| 3363 |
+--------+
shell&amp;gt; mariadb --user=app --password=secret --host=10.139.158.211 --port=3306 customer_0020 --execute='SELECT @@port'
+--------+
| @@port |
+--------+
| 3364 |
+--------+
shell&amp;gt; mariadb --user=app --password=secret --host=10.139.158.211 --port=3306 customer_0030 --execute='SELECT @@port'
+--------+
| @@port |
+--------+
| 3365 |
+--------+
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="less-simple-backup-test"&gt;Less simple (backup) test&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; mariadb-dump --user=app --password=secret --host=10.139.158.211 --port=3306 --single-transaction customer_0010 &amp;gt; /tmp/customer_0010.sql
shell&amp;gt; echo $?
0
shell&amp;gt; mariadb-dump --user=app --password=secret --host=10.139.158.211 --port=3306 --single-transaction customer_0020 &amp;gt; /tmp/customer_0020.sql
shell&amp;gt; echo $?
0
shell&amp;gt; mariadb-dump --user=app --password=secret --host=10.139.158.211 --port=3306 --single-transaction customer_0030 &amp;gt; /tmp/customer_0030.sql
shell&amp;gt; echo $?
0
shell&amp;gt; mariadb-dump --user=app --password=secret --host=10.139.158.211 --port=3306 --single-transaction --databases customer_0011 &amp;gt; /tmp/customer_0011.sql
shell&amp;gt; echo $?
0
shell&amp;gt; mariadb-dump --user=app --password=secret --host=10.139.158.211 --port=3306 --single-transaction --databases customer_0021 &amp;gt; /tmp/customer_0021.sql
shell&amp;gt; echo $?
0
shell&amp;gt; mariadb-dump --user=app --password=secret --host=10.139.158.211 --port=3306 --single-transaction --databases customer_0030 &amp;gt; /tmp/customer_0030.sql
shell&amp;gt; echo $?
0

shell&amp;gt; ll /tmp/customer_00*sql
-rw-rw-r-- 1 oli oli 2738 Mar 18 12:07 /tmp/customer_0010.sql
-rw-rw-r-- 1 oli oli 2904 Mar 18 12:08 /tmp/customer_0011.sql
-rw-rw-r-- 1 oli oli 2712 Mar 18 12:08 /tmp/customer_0020.sql
-rw-rw-r-- 1 oli oli 2906 Mar 18 12:08 /tmp/customer_0021.sql
-rw-rw-r-- 1 oli oli 2964 Mar 18 12:08 /tmp/customer_0030.sql

shell&amp;gt; tail -n 1 /tmp/customer_*.sql
==&amp;gt; /tmp/customer_0010.sql &amp;lt;==
-- Dump completed on 2024-02-13 14:39:21

==&amp;gt; /tmp/customer_0011.sql &amp;lt;==
-- Dump completed on 2024-02-13 14:39:35

==&amp;gt; /tmp/customer_0020.sql &amp;lt;==
-- Dump completed on 2024-02-13 14:40:15

==&amp;gt; /tmp/customer_0021.sql &amp;lt;==
-- Dump completed on 2024-02-13 14:40:42

==&amp;gt; /tmp/customer_0030.sql &amp;lt;==
-- Dump completed on 2024-02-13 14:40:52

shell&amp;gt; cat /tmp/customer_00*sql | grep -A1 -i insert
INSERT INTO `address` VALUES
(1,'Customer 10 GmbH');
--
INSERT INTO `sales` VALUES
(1,'Apples',5,1.20,6.00),
--
INSERT INTO `address` VALUES
(1,'Customer 11 SE');
--
INSERT INTO `sales` VALUES
(1,'Oranges',2,1.70,3.40),
--
INSERT INTO `address` VALUES
(1,'Customer 20 AG');
--
INSERT INTO `sales` VALUES
(1,'Oranges',2,1.70,3.40),
--
INSERT INTO `address` VALUES
(1,'Customer 21 GmbH');
--
INSERT INTO `sales` VALUES
(1,'Oranges',2,1.70,3.40),
--
INSERT INTO `address` VALUES
(1,'Customer 30 GmbH');
--
INSERT INTO `sales` VALUES
(1,'Pickles',2,2.20,4.40),
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In MaxScale 23.08.4 there was a pretty bad bug: A return value of 0 but no data in the backup!!! See also the tickets: &lt;a href="https://jira.mariadb.org/browse/MXS-4966" target="_blank"&gt;MXS-4966: mariadb-dump gets an error dumping schemas&lt;/a&gt; and &lt;a href="https://jira.mariadb.org/browse/MXS-4947" target="_blank"&gt;MXS-4947: Tables in information_schema are treated as a normal tables&lt;/a&gt;. Symptoms of the bug look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Error: Couldn't read status information for table address ()
Error: Couldn't read status information for table sales ()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We therefore strongly recommend upgrading to MaxScale 23.08.5!&lt;/p&gt;
&lt;h3 id="more-complex-application-tests"&gt;More complex application tests&lt;/h3&gt;
&lt;p&gt;We have created a somewhat more complex test (&lt;code&gt;./sharding_test.php&lt;/code&gt;) that processes the following queries:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SET NAMES utf8mb4
SHOW DATABASES
use customer_
START TRANSACTION;
SELECT MIN(id) AS first, MAX(id) AS last FROM `sales`
INSERT INTO sales (id, product, sales, amount, total_amount) VALUES (%d, '%s', %f, %f, %f)
INSERT INTO sales (id, product, sales, sales, amount, total_amount) VALUES (%d, '%s', %f, %f, %f)
UPDATE sales SET product = 'Prepare to delete' WHERE id = %d
DELETE FROM sales WHERE id = %d
COMMIT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This test ran flawlessly. The corresponding control query:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SELECT * FROM customer_0021.sales WHERE id &amp;gt;= (SELECT MAX(id) - 10 FROM customer_0021.sales);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Various load scenarios can also be tested with &lt;code&gt;db_bench&lt;/code&gt; or the Acronis &lt;code&gt;perfkit&lt;/code&gt;. For more information, see &lt;a href="https://www.fromdual.com/mariadb-and-mysql-benchmarking#database-benchmark" target="_blank"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="cross-shard-tests"&gt;Cross-shard tests&lt;/h3&gt;
&lt;p&gt;In any case, you might come up with the idea of running cross-shard queries. This will NOT work, which should not really be surprising, firstly because it is not easy to implement and secondly because it is described here:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Note: As the sharding solution in MaxScale is relatively simple, cross-database queries between two or more shards are not supported.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt;: &lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-simple-sharding-with-two-servers/" target="_blank"&gt;Simple Sharding with Two Servers&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;USE db1 is routed to the server with db1. If the database is divided to multiple servers, only one server will get the command.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt;: &lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-schemarouter/" target="_blank"&gt;SchemaRouter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here is a test with &lt;code&gt;UNION&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; use customer_0030
Database changed
SQL&amp;gt; SELECT * FROM customer_0020.sales UNION SELECT * FROM customer_0030.sales;
ERROR 1146 (42S02): Table 'customer_0020.sales' doesn't exist
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here is the proof to the contrary:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; use customer_0020
Database changed
SQL&amp;gt; SELECT * FROM customer_0020.sales UNION SELECT * FROM customer_0030.sales;
ERROR 1146 (42S02): Table 'customer_0030.sales' doesn't exist
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here is the test with &lt;code&gt;JOIN&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; use customer_0020
SQL&amp;gt; SELECT *
 FROM customer_0020.sales a
 JOIN customer_0030.sales b ON a.id = b.id
WHERE a.sales &amp;gt; 1
;
ERROR 1146 (42S02): Table 'customer_0030.sales' doesn't exist

SQL&amp;gt; use customer_0030

SQL&amp;gt; SELECT *
 FROM customer_0020.sales a
 JOIN customer_0030.sales b ON a.id = b.id
WHERE a.sales &amp;gt; 1
;
ERROR 1146 (42S02): Table 'customer_0020.sales' doesn't exist
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="operation-of-a-maxscale-sharding-system"&gt;Operation of a MaxScale sharding system&lt;/h2&gt;
&lt;p&gt;In this chapter we discuss some points that can be useful for the operation of a MariaDB MaxScale sharding system.&lt;/p&gt;
&lt;h3 id="do-on-all-shards"&gt;Do-on-all-shards&lt;/h3&gt;
&lt;p&gt;Since it can always happen that O/S or database operations have to be executed on all shards, it would certainly make sense to create a script that executes the same command on all shards in turn:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; ./do-on-all-shards.sh --sql='SHOW DATABASES'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A script of this type should greatly reduce the error rate during operation. Operations such as the re-sharding of a tenant, as described below, are also sensibly scripted and executed centrally (&lt;a href="https://jira.mariadb.org/browse/MXS-5029" target="_blank"&gt;MXS-5029&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id="invalidating-the-database-map-cache"&gt;Invalidating the database map cache&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;invalidate&lt;/code&gt; command can be used to invalidate the database map cache of the MariaDB MaxScale SchemaRouter. This allows us to quickly update the cache after adding or removing tenants.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl call command schemarouter invalidate Sharded-Service
OK
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In contrast to the &lt;code&gt;invalidate&lt;/code&gt; command, which updates the entries after the next &lt;code&gt;refresh_interval&lt;/code&gt;, the &lt;code&gt;clear&lt;/code&gt; command deletes the entries and a remap is executed immediately.&lt;/p&gt;
&lt;p&gt;If you want to invalidate the database map cache remotely with a REST API call, you can do this as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; curl -i -X POST -u api_admin:secret http://10.139.158.211:8989/v1/maxscale/modules/schemarouter/clear?Sharded-Service
HTTP/1.1 204 No Content
Connection: close
Date: Mon, 18 Mar 24 11:49:58 GMT
X-Frame-Options: Deny
X-XSS-Protection: 1
Referrer-Policy: same-origin
Cache-Control: no-cache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-schemarouter/#module-commands" target="_blank"&gt;Schema Router - Module commands&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-maxscale-resource/#call-a-module-command" target="_blank"&gt;Call a module command&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-rest-api/" target="_blank"&gt;MaxScale REST API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="how-to-change-schemarouter-variables-dynamically"&gt;How to change SchemaRouter variables dynamically?&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;refresh_interval&lt;/code&gt; specifies the lifetime of the entries in the SchemaRouter Database Map Cache. The default value is 300 s (5 min). Refresh Interval is therefore, in my opinion, an unfortunate term as it does not define the interval between two mappings but the lifetime of the cache entries (livetime?, timeout?). As soon as the entry has been deleted, a new refresh of the &amp;ldquo;database map&amp;rdquo; is triggered on each shard. The command currently looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT LOWER(t.table_schema), LOWER(t.table_name) FROM information_schema.tables t
 UNION ALL
SELECT LOWER(s.schema_name), '' FROM information_schema.schemata s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It looks like a simple connect is enough to trigger the refresh of the database map.&lt;/p&gt;
&lt;p&gt;The current value for &lt;code&gt;refresh_interval&lt;/code&gt; can be queried as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl show service Sharded-Service | grep refresh_interval | awk -F'│' '{ print $3 }'
 &amp;quot;refresh_interval&amp;quot;: &amp;quot;300000ms&amp;quot;,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following command helps to change the value dynamically:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; MAXCTRL_WARNINGS=0 maxctrl alter service Sharded-Service refresh_interval=10s
OK
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The value should not be set too small, as all other connections are stopped during the mapping process.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sources&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-schemarouter/#refresh_interval" target="_blank"&gt;MariaDB MaxScale SchemaRouter - refresh_interval&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-schemarouter/#refresh_databases" target="_blank"&gt;MariaDB MaxScale SchemaRouter - refresh_database&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="adding-and-removing-a-tenant"&gt;Adding and removing a tenant&lt;/h3&gt;
&lt;p&gt;Adding a new tenant to a shard is not a major problem:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; CREATE DATABASE customer_0029;
SQL&amp;gt; use customer_0029
SQL&amp;gt; CREATE TABLE address LIKE customer_template.address;
SQL&amp;gt; CREATE TABLE sales LIKE customer_template.sales;

shell&amp;gt; maxctrl call command schemarouter invalidate Sharded-Service
OK
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Removing a tenant from a shard, on the other hand, is somewhat more complicated and must be done in consultation with the application:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; DROP DATABASE customer_0011;

shell&amp;gt; ./sharding_test.php
.....ERROR: Table 'customer_0011.sales' doesn't exist...ERROR: Unknown database 'customer_0011'.ERROR: Unknown database 'customer_0011'......ERROR: Unknown database 'customer_0011'...

shell&amp;gt; maxctrl call command schemarouter clear Sharded-Service
OK
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At least I have not come up with a cleverer variant yet. See also Moving a tenant below.&lt;/p&gt;
&lt;h3 id="moving-a-tenant"&gt;Moving a tenant&lt;/h3&gt;
&lt;p&gt;The combination of adding and removing would then be moving a tenant from one shard to another shard, also known as re-sharding. This also requires a concerted action to be planned together with the application.&lt;/p&gt;
&lt;p&gt;If this is not possible, at least the time that the application receives errors can be reduced&amp;hellip; The following procedure can be used to move a tenant from shard 2 to shard 3:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; use customer_0020; LOCK TABLES address READ, sales READ; -- On Shard 2, application will be blocked at best!

shell&amp;gt; mariadb-dump --user=app --password=secret --host=10.139.158.1 --port=3364 --single-transaction --skip-add-locks --databases customer_0020 | mariadb --user=app --password=secret --host=10.139.158.1 --port=3365 # Copy tenant 20 from shard 2 to shard 3

SQL&amp;gt; DROP DATABASE customer_0020; -- Deleting tenant 20 does not work!
ERROR 1192 (HY000): Can't execute the given command because you have active locked tables or an active transaction

SQL&amp;gt; UNLOCK TABLES; DROP DATABASE customer_0020; # How to delete tenant 20.

shell&amp;gt; maxctrl call command schemarouter clear Sharded-Service # Update MaxScale Database Map. Do it quickly!!!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Until the database map is refreshed, the following errors may occur:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;error : (47621) [schemarouter] (Sharded-Service); 'customer_0020.' found on servers 'shard2','shard3' for user 'app'@'10.139.158.1'.
error : (47621) [schemarouter] (Sharded-Service); 'customer_0020.address' found on servers 'shard2','shard3' for user 'app'@'10.139.158.1'.
error : (47621) [schemarouter] (Sharded-Service); 'customer_0020.sales' found on servers 'shard2','shard3' for user 'app'@'10.139.158.1'.
error : (47621) [schemarouter] (Sharded-Service); Duplicate tables found, closing session.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And on the application side too:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ERROR: Error: duplicate tables found on two different shards
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="adding-or-removing-a-shard"&gt;Adding or removing a shard&lt;/h3&gt;
&lt;p&gt;Moving a tenant from one shard to another shard is a small re-sharding operation. It becomes somewhat more complex if you want to add new shards or remove old shards. Subsequently (after the addition or before the removal), a large re-sharding would then take place. The first step is to add a shard to the cluster:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl list servers
┌────────┬──────────────┬──────┬─────────────┬─────────┬───────────────┬──────────────────┐
│ Server │ Address │ Port │ Connections │ State │ GTID │ Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼───────────────┼──────────────────┤
│ shard1 │ 10.139.158.1 │ 3363 │ 0 │ Running │ 0-3363-26014 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼───────────────┼──────────────────┤
│ shard2 │ 10.139.158.1 │ 3364 │ 0 │ Running │ 0-3364-240612 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼───────────────┼──────────────────┤
│ shard3 │ 10.139.158.1 │ 3365 │ 0 │ Running │ 0-3365-289873 │ Sharding-Monitor │
└────────┴──────────────┴──────┴─────────────┴─────────┴───────────────┴──────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The prepared shard is made known to MaxScale:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl create server shard4 10.139.158.1 3366
OK

shell&amp;gt; maxctrl list servers
┌────────┬──────────────┬──────┬─────────────┬─────────┬──────────────┬──────────────────┐
│ Server │ Address │ Port │ Connections │ State │ GTID │ Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard1 │ 10.139.158.1 │ 3363 │ 1 │ Running │ 0-3363-23676 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard2 │ 10.139.158.1 │ 3364 │ 1 │ Running │ 0-3364-52321 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard3 │ 10.139.158.1 │ 3365 │ 1 │ Running │ 0-3365-39751 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard4 │ 10.139.158.1 │ 3366 │ 0 │ Down │ │ │
└────────┴──────────────┴──────┴─────────────┴─────────┴──────────────┴──────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The new shard is then linked to the MaxScale Monitor and the service:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; MAXCTRL_WARNINGS=0 maxctrl link monitor Sharding monitor shard4
OK

shell&amp;gt; MAXCTRL_WARNINGS=0 maxctrl link service Sharded service shard4
OK

shell&amp;gt; maxctrl list servers
┌────────┬──────────────┬──────┬─────────────┬─────────┬──────────────┬──────────────────┐
│ Server │ Address │ Port │ Connections │ State │ GTID │ Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard1 │ 10.139.158.1 │ 3363 │ 1 │ Running │ 0-3363-24961 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard2 │ 10.139.158.1 │ 3364 │ 1 │ Running │ 0-3364-56215 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard3 │ 10.139.158.1 │ 3365 │ 1 │ Running │ 0-3365-45177 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard4 │ 10.139.158.1 │ 3366 │ 1 │ Running │ 0-3366-32 │ Sharding-Monitor │
└────────┴──────────────┴──────┴─────────────┴─────────┴──────────────┴──────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Whether this second step is also absolutely necessary was not investigated.&lt;/p&gt;
&lt;p&gt;You can follow the entire process in the MariaDB MaxScale error log:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;warning: Discarding journal file '/var/lib/maxscale/Sharding-Monitor_journal.json'. Servers described in the journal are different from the ones configured on the current monitor.
warning: Saving runtime modifications to 'Sharding-Monitor' in '/var/lib/maxscale/maxscale.cnf.d/Sharding-Monitor.cnf'. The modified values will override the values found in the static configuration files.
notice : shard4 sent version string '10.11.7-MariaDB-log'. Detected type: MariaDB, version: 10.11.7.
notice : Server 'shard4' charset: latin1_swedish_ci
notice : Server changed state: shard4[10.139.158.1:3366]: server_up. [Down]→[Running]
warning: Saving runtime modifications to 'Sharded-Service' in '/var/lib/maxscale/maxscale.cnf.d/Sharded-Service.cnf'. The modified values will override the values found in the static configuration files.
notice : Added 'shard4' to 'Sharded-Service'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What we must not forget here is to also equip the new shard with the proxy protocol:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl show server shard4 | grep proxy
│ │ &amp;quot;proxy_protocol&amp;quot;: false, │

MAXCTRL_WARNINGS=0 maxctrl alter server shard4 proxy_protocol=true
OK
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And now new tenants can be added to the new shard or old tenants can be moved to the new shard&amp;hellip; In our setup, we want to move all tenants from shard 1 to shard 4 and also create a new tenant &lt;code&gt;customer_0040&lt;/code&gt; on shard 4. The individual steps required for this are listed above.&lt;/p&gt;
&lt;p&gt;Once shard 1 has been emptied, it can be dismantled:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl list servers
┌────────┬──────────────┬──────┬─────────────┬─────────┬──────────────┬──────────────────┐
│ Server │ Address │ Port │ Connections │ State │ GTID │ Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard1 │ 10.139.158.1 │ 3363 │ 1 │ Running │ 0-3363-25916 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard2 │ 10.139.158.1 │ 3364 │ 1 │ Running │ 0-3364-62887 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard3 │ 10.139.158.1 │ 3365 │ 1 │ Running │ 0-3365-54035 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard4 │ 10.139.158.1 │ 3366 │ 1 │ Running │ 0-3366-2247 │ Sharding-Monitor │
└────────┴──────────────┴──────┴─────────────┴─────────┴──────────────┴──────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A shard is deleted with the &lt;code&gt;destroy server&lt;/code&gt; command. Before this works, however, a shard must be removed from the monitor and the service:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; MAXCTRL_WARNINGS=0 maxctrl unlink service Sharded service shard1
OK

shell&amp;gt; MAXCTRL_WARNINGS=0 maxctrl unlink monitor Sharding monitor shard1
OK

shell&amp;gt; maxctrl list servers
┌────────┬──────────────┬──────┬─────────────┬─────────┬──────────────┬──────────────────┐
│ Server │ Address │ Port │ Connections │ State │ GTID │ Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard1 │ 10.139.158.1 │ 3363 │ 0 │ Running │ │ │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard2 │ 10.139.158.1 │ 3364 │ 1 │ Running │ 0-3364-64394 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard3 │ 10.139.158.1 │ 3365 │ 1 │ Running │ 0-3365-56072 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard4 │ 10.139.158.1 │ 3366 │ 1 │ Running │ 0-3366-3267 │ Sharding-Monitor │
└────────┴──────────────┴──────┴─────────────┴─────────┴──────────────┴──────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the shard has been removed from the monitor and the service, it can then be deleted:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl destroy server shard1
Warning: Object 'shard1' is defined in a static configuration file and cannot be permanently deleted. If MaxScale is restarted, the object will appear again.
To hide these warnings, run:

 export MAXCTRL_WARNINGS=0

OK
shell&amp;gt; maxctrl list servers
┌────────┬──────────────┬──────┬─────────────┬─────────┬──────────────┬──────────────────┐
│ Server │ Address │ Port │ Connections │ State │ GTID │ Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard2 │ 10.139.158.1 │ 3364 │ 1 │ Running │ 0-3364-65018 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard3 │ 10.139.158.1 │ 3365 │ 1 │ Running │ 0-3365-56886 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard4 │ 10.139.158.1 │ 3366 │ 1 │ Running │ 0-3366-3648 │ Sharding-Monitor │
└────────┴──────────────┴──────┴─────────────┴─────────┴──────────────┴──────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you can follow the changes in the MaxScale Error Log:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;notice : Removed 'shard1' from 'Sharded-Service'
warning: Discarding journal file '/var/lib/maxscale/Sharding-Monitor_journal.json'. Servers described in the journal are different from the ones configured on the current monitor.
notice : Destroyed server 'shard1' at 10.139.158.1:3363
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: I was informed that with &lt;code&gt;destroy server --force&lt;/code&gt; the &lt;code&gt;unlink service&lt;/code&gt; and &lt;code&gt;unlink monitor&lt;/code&gt; commands are automatically executed by MaxScale.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-mariadb-maxscale-administration-tutorial/#managing-servers" target="_blank"&gt;MariaDB MaxScale Administration Tutorial - Managing servers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="customising-the-configuration-files"&gt;Customising the configuration files&lt;/h3&gt;
&lt;p&gt;During the shard operations described above we received some warnings:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Warning: Object 'shard1' is defined in a static configuration file and cannot be permanently deleted. If MaxScale is restarted, the object will appear again.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Warning: Saving runtime modifications to 'Sharding-Monitor' in '/var/lib/maxscale/maxscale.cnf.d/Sharding-Monitor.cnf'. The modified values will override the values found in the static configuration files.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The corresponding configuration files are automatically created by MaxScale when dynamic system changes are made:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; ll /var/lib/maxscale/maxscale.cnf.d/ /etc/maxscale.cnf
-rw-r--r-- 1 root root 612 Feb 13 14:23 /etc/maxscale.cnf

/var/lib/maxscale/maxscale.cnf.d/:
total 12
-rw------- 1 maxscale maxscale 187 Feb 13 16:08 Sharding-Monitor.cnf
-rw------- 1 maxscale maxscale 150 Feb 13 16:07 Sharded-Service.cnf
-rw------- 1 maxscale maxscale 52 Feb 13 15:46 shard4.cnf

cat /var/lib/maxscale/maxscale.cnf.d/*
[Sharded-Service]
debug=true
refresh_interval=10000ms
auth_all_servers=true
log_debug=true
password=secret
router=schemarouter
type=service
user=maxscale_admin
targets=shard2,shard3,shard4

[sharding monitor]
module=galeramon
monitor_interval=1000ms
password=secret
servers=shard2,shard3,shard4
type=monitor
user=maxscale_monitor

[shard4]
address=10.139.158.1
port=3366
type=server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The configuration files still need to be improved accordingly. You should generally consider whether you should not configure everything dynamically via commands in a highly dynamic system&amp;hellip;&lt;/p&gt;
&lt;h3 id="maintenance-work-on-the-shard"&gt;Maintenance work on the shard&lt;/h3&gt;
&lt;p&gt;If a shard is to be taken offline for maintenance work, here in the example &lt;code&gt;shard2&lt;/code&gt;, this can be done as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl list servers
┌────────┬──────────────┬──────┬─────────────┬─────────┬──────────────┬──────────────────┐
│ Server │ Address │ Port │ Connections │ State │ GTID │ Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard2 │ 10.139.158.1 │ 3364 │ 1 │ Running │ 0-3364-69817 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard3 │ 10.139.158.1 │ 3365 │ 1 │ Running │ 0-3365-63166 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼──────────────┼──────────────────┤
│ shard4 │ 10.139.158.1 │ 3366 │ 1 │ Running │ 0-3366-6902 │ Sharding-Monitor │
└────────┴──────────────┴──────┴─────────────┴─────────┴──────────────┴──────────────────┘

shell&amp;gt; maxctrl set server shard2 drain
OK

shell&amp;gt; maxctrl set server shard2 maintenance
OK

shell&amp;gt; maxctrl list servers
┌────────┬──────────────┬──────┬─────────────┬──────────────────────┬───────────────┬──────────────────┐
│ Server │ Address │ Port │ Connections │ State │ GTID │ Monitor │
├────────┼──────────────┼──────┼─────────────┼──────────────────────┼───────────────┼──────────────────┤
│ shard2 │ 10.139.158.1 │ 3364 │ 0 │ Maintenance, Running │ 0-3364-240612 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼──────────────────────┼───────────────┼──────────────────┤
│ shard3 │ 10.139.158.1 │ 3365 │ 0 │ Running │ 0-3365-289873 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼──────────────────────┼───────────────┼──────────────────┤
│ shard4 │ 10.139.158.1 │ 3366 │ 0 │ Running │ 0-3366-119848 │ Sharding-Monitor │
└────────┴──────────────┴──────┴─────────────┴──────────────────────┴───────────────┴──────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, maintenance work can be carried out on the machine or the database&amp;hellip;&lt;/p&gt;
&lt;p&gt;Afterwards, BOTH statuses must be cleared again if both have been set (&lt;a href="https://jira.mariadb.org/browse/MXS-5028" target="_blank"&gt;MXS-5028&lt;/a&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl clear server shard2 maintenance
OK

shell&amp;gt; maxctrl clear server shard2 drain
OK

shell&amp;gt; maxctrl list servers
┌────────┬──────────────┬──────┬─────────────┬─────────┬───────────────┬──────────────────┐
│ Server │ Address │ Port │ Connections │ State │ GTID │ Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼───────────────┼──────────────────┤
│ shard2 │ 10.139.158.1 │ 3364 │ 0 │ Running │ 0-3364-240612 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼───────────────┼──────────────────┤
│ shard3 │ 10.139.158.1 │ 3365 │ 0 │ Running │ 0-3365-289873 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼───────────────┼──────────────────┤
│ shard4 │ 10.139.158.1 │ 3366 │ 0 │ Running │ 0-3366-119848 │ Sharding-Monitor │
└────────┴──────────────┴──────┴─────────────┴─────────┴───────────────┴──────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The difference between &lt;code&gt;drain&lt;/code&gt; and &lt;code&gt;maintenance&lt;/code&gt; is that with &lt;code&gt;drain&lt;/code&gt;, no new connections are allowed to the shard, but existing connections wait until they are closed. With &lt;code&gt;maintenance&lt;/code&gt;, the connections are terminated immediately by force.&lt;/p&gt;
&lt;h2 id="observation-of-a-mariadb-maxscale-sharding-system"&gt;Observation of a MariaDB MaxScale sharding system&lt;/h2&gt;
&lt;p&gt;The MaxScale CLI client &lt;code&gt;maxtrl&lt;/code&gt; can be used to query the status of the MariaDB MaxScale load balancer. There are numerous commands for this, mainly &lt;code&gt;list&lt;/code&gt; and &lt;code&gt;show&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl show module schemarouter | head -n 12
┌─────────────┬────────────────────────────────────────────────┐
│ Module │ schemarouter │
├─────────────┼────────────────────────────────────────────────┤
│ Type │ Router │
├─────────────┼────────────────────────────────────────────────┤
│ Version │ V1.0.0 │
├─────────────┼────────────────────────────────────────────────┤
│ Maturity │ Beta │
├─────────────┼────────────────────────────────────────────────┤
│ Description │ A database sharding router for simple sharding │
├─────────────┼────────────────────────────────────────────────┤
│ Parameters │ ... │

shell&amp;gt; maxctrl list servers
┌────────┬──────────────┬──────┬─────────────┬─────────┬───────────────┬──────────────────┐
│ Server │ Address │ Port │ Connections │ State │ GTID │ Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼───────────────┼──────────────────┤
│ shard2 │ 10.139.158.1 │ 3364 │ 4 │ Running │ 0-3364-290859 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼───────────────┼──────────────────┤
│ shard3 │ 10.139.158.1 │ 3365 │ 4 │ Running │ 0-3365-322671 │ Sharding-Monitor │
├────────┼──────────────┼──────┼─────────────┼─────────┼───────────────┼──────────────────┤
│ shard4 │ 10.139.158.1 │ 3366 │ 4 │ Running │ 0-3366-140018 │ Sharding-Monitor │
└────────┴──────────────┴──────┴─────────────┴─────────┴───────────────┴──────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The information for the Connections column is confusing because in this case we only have 1, 1 and 2 connections open on each shard in this sharding system.&lt;/p&gt;
&lt;p&gt;However, if you look at the situation on the respective shard with &lt;code&gt;SHOW PROCESSLIST&lt;/code&gt;, you can see that MaxScale also establishes a connection on EACH shard for each incoming connection. So the display above is actually technically correct, just not what you would expect:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SHOW PROCESSLIST;
+--------+------------------+----------------------+---------------+---------+------+----------+-----------------------------------------------------------------+----------+
| Id | User | Host | db | Command | Time | State | Info | Progress |
+--------+------------------+----------------------+---------------+---------+------+----------+-----------------------------------------------------------------+----------+
| 123 | root | localhost | customer_0021 | Query | 0 | starting | show processlist | 0.000 |
| 68107 | maxscale_monitor | 10.139.158.211:35418 | NULL | Sleep | 0 | | NULL | 0.000 |
| 113372 | app | 10.139.158.1:47548 | NULL | Sleep | 47 | | NULL | 0.000 |
| 113538 | app | 10.139.158.1:49058 | NULL | Sleep | 41 | | NULL | 0.000 |
| 113662 | app | 10.139.158.1:47072 | NULL | Sleep | 37 | | NULL | 0.000 |
| 114789 | app | 10.139.158.1:39574 | customer_0022 | Query | 0 | Updating | UPDATE sales SET product = 'Prepare to delete' WHERE id = 15622 | 0.000 |
+--------+------------------+----------------------+---------------+---------+------+----------+-----------------------------------------------------------------+----------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This does not scale with large systems with hundreds or thousands of clients! Maybe the &lt;a href="https://mariadb.com/kb/en/thread-pool-in-mariadb/" target="_blank"&gt;MariaDB thread pool&lt;/a&gt; feature is used in this case.&lt;/p&gt;
&lt;p&gt;According to the MaxScale developer, this is expected behaviour&amp;hellip; (&lt;a href="https://jira.mariadb.org/browse/MXS-4977" target="_blank"&gt;MXS-4977&lt;/a&gt;)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl list services
┌─────────────────┬──────────────┬─────────────┬───────────────────┬────────────────────────┐
│ Service │ Router │ Connections │ Total Connections │ Targets │
├─────────────────┼──────────────┼─────────────┼───────────────────┼────────────────────────┤
│ Sharded-Service │ schemarouter │ 4 │ 82776 │ shard2, shard3, shard4 │
└─────────────────┴──────────────┴─────────────┴───────────────────┴────────────────────────┘

shell&amp;gt; maxctrl list listeners
┌──────────────────────────┬──────┬──────┬─────────┬─────────────────┐
│ Name │ Port │ Host │ State │ Service │
├──────────────────────────┼──────┼──────┼─────────┼─────────────────┤
│ Sharded-Service-Listener │ 3306 │ :: │ Running │ Sharded-Service │
└──────────────────────────┴──────┴──────┴─────────┴─────────────────┘

shell&amp;gt; maxctrl list monitors
┌──────────────────┬─────────┬────────────────────────┐
│ Monitor │ State │ Servers │
├──────────────────┼─────────┼────────────────────────┤
│ Sharding-Monitor │ Running │ shard2, shard3, shard4 │
└──────────────────┴─────────┴────────────────────────┘

shell&amp;gt; maxctrl show server shard2 | head -n 20
┌─────────────────────┬──────────────────────────────────────────────┐
│ Server │ shard2 │
├─────────────────────┼──────────────────────────────────────────────┤
│ Source │ /etc/maxscale.cnf │
├─────────────────────┼──────────────────────────────────────────────┤
│ Address │ 10.139.158.1 │
├─────────────────────┼──────────────────────────────────────────────┤
│ Port │ 3364 │
├─────────────────────┼──────────────────────────────────────────────┤
│ State │ Running │
├─────────────────────┼──────────────────────────────────────────────┤
│ Version │ 10.11.7-MariaDB-log │
├─────────────────────┼──────────────────────────────────────────────┤
│ Uptime │ 178960 │
├─────────────────────┼──────────────────────────────────────────────┤
│ Last Event │ server_down │
├─────────────────────┼──────────────────────────────────────────────┤
│ Triggered At │ Sun, 04 Feb 2024 07:37:17 GMT │
├─────────────────────┼──────────────────────────────────────────────┤
│ Services │ Sharded-Service │
├─────────────────────┼──────────────────────────────────────────────┤
│ Monitors │ Sharding-Monitor │
├─────────────────────┼──────────────────────────────────────────────┤
...
├─────────────────────┼──────────────────────────────────────────────┤
│ Current Connections │ 5 │
├─────────────────────┼──────────────────────────────────────────────┤
│ Total Connections │ 27 │
├─────────────────────┼──────────────────────────────────────────────┤
│ Max Connections │ 5 │

shell&amp;gt; maxctrl show service Sharded-Service
┌─────────────────────┬──────────────────────────────────────────────────────┐
│ Service │ Sharded-Service │
├─────────────────────┼──────────────────────────────────────────────────────┤
│ Source │ /var/lib/maxscale/maxscale.cnf.d/Sharded-Service.cnf │
├─────────────────────┼──────────────────────────────────────────────────────┤
│ Router │ schemarouter │
├─────────────────────┼──────────────────────────────────────────────────────┤
│ State │ Started │
├─────────────────────┼──────────────────────────────────────────────────────┤
│ Started At │ 3/18/2024, 1:52:30 PM │
├─────────────────────┼──────────────────────────────────────────────────────┤
│ Users Loaded At │ 3/18/2024, 1:52:30 PM │
├─────────────────────┼──────────────────────────────────────────────────────┤
│ Current Connections │ 4 │
├─────────────────────┼──────────────────────────────────────────────────────┤
│ Total Connections │ 84590 │
├─────────────────────┼──────────────────────────────────────────────────────┤
│ Max Connections │ 5 │
├─────────────────────┼──────────────────────────────────────────────────────┤
│ Cluster │ │
├─────────────────────┼──────────────────────────────────────────────────────┤
│ Servers │ shard2 │
│ │ shard3 │
│ │ shard4 │
├─────────────────────┼──────────────────────────────────────────────────────┤
│ Services │ │
├─────────────────────┼──────────────────────────────────────────────────────┤
│ Filters │ │
├─────────────────────┼──────────────────────────────────────────────────────┤
│ Parameters │ { │
│ │ &amp;quot;auth_all_servers&amp;quot;: true, │
│ │ &amp;quot;connection_keepalive&amp;quot;: &amp;quot;300000ms&amp;quot;, │
│ │ &amp;quot;debug&amp;quot;: true, │
│ │ &amp;quot;disable_sescmd_history&amp;quot;: false, │
│ │ &amp;quot;enable_root_user&amp;quot;: false, │
│ │ &amp;quot;force_connection_keepalive&amp;quot;: false, │
│ │ &amp;quot;idle_session_pool_time&amp;quot;: &amp;quot;-1ms&amp;quot;, │
│ │ &amp;quot;ignore_tables&amp;quot;: [], │
│ │ &amp;quot;ignore_tables_regex&amp;quot;: null, │
│ │ &amp;quot;localhost_match_wildcard_host&amp;quot;: true, │
│ │ &amp;quot;log_auth_warnings&amp;quot;: true, │
│ │ &amp;quot;log_debug&amp;quot;: true, │
│ │ &amp;quot;log_info&amp;quot;: false, │
│ │ &amp;quot;log_notice&amp;quot;: false, │
│ │ &amp;quot;log_warning&amp;quot;: false, │
│ │ &amp;quot;max_connections&amp;quot;: 0, │
│ │ &amp;quot;max_sescmd_history&amp;quot;: 50, │
│ │ &amp;quot;max_staleness&amp;quot;: &amp;quot;150000ms&amp;quot;, │
│ │ &amp;quot;multiplex_timeout&amp;quot;: &amp;quot;60000ms&amp;quot;, │
│ │ &amp;quot;net_write_timeout&amp;quot;: &amp;quot;0ms&amp;quot;, │
│ │ &amp;quot;password&amp;quot;: &amp;quot;*****&amp;quot;, │
│ │ &amp;quot;prune_sescmd_history&amp;quot;: true, │
│ │ &amp;quot;rank&amp;quot;: &amp;quot;primary&amp;quot;, │
│ │ &amp;quot;refresh_databases&amp;quot;: false, │
│ │ &amp;quot;refresh_interval&amp;quot;: &amp;quot;10000ms&amp;quot;, │
│ │ &amp;quot;retain_last_statements&amp;quot;: -1, │
│ │ &amp;quot;router&amp;quot;: &amp;quot;schemarouter&amp;quot;, │
│ │ &amp;quot;session_trace&amp;quot;: false, │
│ │ &amp;quot;strip_db_esc&amp;quot;: true, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;service&amp;quot;, │
│ │ &amp;quot;user&amp;quot;: &amp;quot;maxscale_admin&amp;quot;, │
│ │ &amp;quot;user_accounts_file&amp;quot;: null, │
│ │ &amp;quot;user_accounts_file_usage&amp;quot;: &amp;quot;add_when_load_ok&amp;quot;, │
│ │ &amp;quot;version_string&amp;quot;: null, │
│ │ &amp;quot;wait_timeout&amp;quot;: &amp;quot;0ms&amp;quot; │
│ │ } │
├─────────────────────┼──────────────────────────────────────────────────────┤
│ Router Diagnostics │ { │
│ │ &amp;quot;average_session&amp;quot;: 0.028822357131634554, │
│ │ &amp;quot;longest_sescmd_chain&amp;quot;: 4, │
│ │ &amp;quot;longest_session&amp;quot;: 50, │
│ │ &amp;quot;queries&amp;quot;: 761134, │
│ │ &amp;quot;sescmd_percentage&amp;quot;: 44.44342257736483, │
│ │ &amp;quot;shard_map_hits&amp;quot;: 84356, │
│ │ &amp;quot;shard_map_misses&amp;quot;: 5, │
│ │ &amp;quot;shard_map_stale&amp;quot;: 229, │
│ │ &amp;quot;shard_map_updates&amp;quot;: 216, │
│ │ &amp;quot;shortest_session&amp;quot;: 0, │
│ │ &amp;quot;times_sescmd_limit_exceeded&amp;quot;: 0 │
│ │ } │
└─────────────────────┴──────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See also &lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-schemarouter/#router-diagnostics" target="_blank"&gt;MaxScale SchemaRouter Router diagnostics&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; maxctrl show monitor Sharding-Monitor
┌─────────────────────┬──────────────────────────────────────────────────────────┐
│ Monitor │ Sharding-Monitor │
├─────────────────────┼──────────────────────────────────────────────────────────┤
│ Source │ /etc/maxscale.cnf │
├─────────────────────┼──────────────────────────────────────────────────────────┤
│ Module │ galeramon │
├─────────────────────┼──────────────────────────────────────────────────────────┤
│ State │ Running │
├─────────────────────┼──────────────────────────────────────────────────────────┤
│ Servers │ shard1 │
│ │ shard2 │
│ │ shard3 │
├─────────────────────┼──────────────────────────────────────────────────────────┤
│ Parameters │ { │
│ │ &amp;quot;available_when_donor&amp;quot;: false, │
│ │ &amp;quot;backend_connect_attempts&amp;quot;: 1, │
│ │ &amp;quot;backend_connect_timeout&amp;quot;: &amp;quot;3000ms&amp;quot;, │
│ │ &amp;quot;backend_read_timeout&amp;quot;: &amp;quot;3000ms&amp;quot;, │
│ │ &amp;quot;backend_write_timeout&amp;quot;: &amp;quot;3000ms&amp;quot;, │
│ │ &amp;quot;disable_master_failback&amp;quot;: false, │
│ │ &amp;quot;disable_master_role_setting&amp;quot;: false, │
│ │ &amp;quot;disk_space_check_interval&amp;quot;: &amp;quot;0ms&amp;quot;, │
│ │ &amp;quot;disk_space_threshold&amp;quot;: null, │
│ │ &amp;quot;events&amp;quot;: &amp;quot;all,master_down,master_up,...,new_donor&amp;quot;, │
│ │ &amp;quot;journal_max_age&amp;quot;: &amp;quot;28800000ms&amp;quot;, │
│ │ &amp;quot;module&amp;quot;: &amp;quot;galeramon&amp;quot;, │
│ │ &amp;quot;monitor_interval&amp;quot;: &amp;quot;1000ms&amp;quot;, │
│ │ &amp;quot;password&amp;quot;: &amp;quot;*****&amp;quot;, │
│ │ &amp;quot;root_node_as_master&amp;quot;: false, │
│ │ &amp;quot;script&amp;quot;: null, │
│ │ &amp;quot;script_timeout&amp;quot;: &amp;quot;90000ms&amp;quot;, │
│ │ &amp;quot;set_donor_nodes&amp;quot;: false, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;monitor&amp;quot;, │
│ │ &amp;quot;use_priority&amp;quot;: false, │
│ │ &amp;quot;user&amp;quot;: &amp;quot;maxscale_monitor&amp;quot; │
│ │ } │
├─────────────────────┼──────────────────────────────────────────────────────────┤
│ Monitor Diagnostics │ { │
│ │ &amp;quot;disable_master_failback&amp;quot;: false, │
│ │ &amp;quot;disable_master_role_setting&amp;quot;: false, │
│ │ &amp;quot;root_node_as_master&amp;quot;: false, │
│ │ &amp;quot;server_info&amp;quot;: [ │
│ │ { │
│ │ &amp;quot;gtid_binlog_pos&amp;quot;: &amp;quot;0-3363-26014&amp;quot;, │
│ │ &amp;quot;gtid_current_pos&amp;quot;: &amp;quot;0-3363-26014&amp;quot;, │
│ │ &amp;quot;master_id&amp;quot;: 0, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;shard1&amp;quot;, │
│ │ &amp;quot;read_only&amp;quot;: false, │
│ │ &amp;quot;server_id&amp;quot;: 3363 │
│ │ }, │
│ │ { │
│ │ &amp;quot;gtid_binlog_pos&amp;quot;: &amp;quot;0-3364-240612&amp;quot;, │
│ │ &amp;quot;gtid_current_pos&amp;quot;: &amp;quot;0-3364-240612&amp;quot;, │
│ │ &amp;quot;master_id&amp;quot;: 0, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;shard2&amp;quot;, │
│ │ &amp;quot;read_only&amp;quot;: false, │
│ │ &amp;quot;server_id&amp;quot;: 3364 │
│ │ }, │
│ │ { │
│ │ &amp;quot;gtid_binlog_pos&amp;quot;: &amp;quot;0-3365-289873&amp;quot;, │
│ │ &amp;quot;gtid_current_pos&amp;quot;: &amp;quot;0-3365-289873&amp;quot;, │
│ │ &amp;quot;master_id&amp;quot;: 0, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;shard3&amp;quot;, │
│ │ &amp;quot;read_only&amp;quot;: false, │
│ │ &amp;quot;server_id&amp;quot;: 3365 │
│ │ } │
│ │ ], │
│ │ &amp;quot;set_donor_nodes&amp;quot;: false, │
│ │ &amp;quot;use_priority&amp;quot;: false │
│ │ } │
└─────────────────────┴──────────────────────────────────────────────────────────┘

shell&amp;gt; maxctrl list sessions;
┌───────┬──────┬──────────────┬───────────────────────┬───────┬─────────────────┬────────┬──────────────┐
│ Id │ User │ Host │ Connected │ Idle │ Service │ Memory │ I/O-Activity │
├───────┼──────┼──────────────┼───────────────────────┼───────┼─────────────────┼────────┼──────────────┤
│ 87240 │ app │ 10.139.158.1 │ 3/18/2024, 2:33:54 PM │ 0 │ Sharded-Service │ 68644 │ 33 │
├───────┼──────┼──────────────┼───────────────────────┼───────┼─────────────────┼────────┼──────────────┤
│ 72654 │ app │ 10.139.158.1 │ 3/18/2024, 2:25:27 PM │ 506.3 │ Sharded-Service │ 199328 │ 0 │
├───────┼──────┼──────────────┼───────────────────────┼───────┼─────────────────┼────────┼──────────────┤
│ 72364 │ app │ 10.139.158.1 │ 3/18/2024, 2:25:18 PM │ 516 │ Sharded-Service │ 199328 │ 0 │
├───────┼──────┼──────────────┼───────────────────────┼───────┼─────────────────┼────────┼──────────────┤
│ 72530 │ app │ 10.139.158.1 │ 3/18/2024, 2:25:23 PM │ 510.5 │ Sharded-Service │ 199328 │ 0 │
└───────┴──────┴──────────────┴───────────────────────┴───────┴─────────────────┴────────┴──────────────┘

shell&amp;gt; maxctrl show session 26
┌───────────────────────┬───────────────────────────────────────┐
│ Id │ 26 │
├───────────────────────┼───────────────────────────────────────┤
│ Service │ Sharded-Service │
├───────────────────────┼───────────────────────────────────────┤
│ State │ Session started │
├───────────────────────┼───────────────────────────────────────┤
│ User │ app │
├───────────────────────┼───────────────────────────────────────┤
│ Host │ 10.139.158.1 │
├───────────────────────┼───────────────────────────────────────┤
│ Port │ 42854 │
├───────────────────────┼───────────────────────────────────────┤
│ Database │ │
├───────────────────────┼───────────────────────────────────────┤
│ Connected │ 2/4/2024, 9:31:12 AM │
├───────────────────────┼───────────────────────────────────────┤
│ Idle │ 610.4 │
├───────────────────────┼───────────────────────────────────────┤
│ Parameters │ { │
│ │ &amp;quot;log_error&amp;quot;: false, │
│ │ &amp;quot;log_info&amp;quot;: false, │
│ │ &amp;quot;log_notice&amp;quot;: false, │
│ │ &amp;quot;log_warning&amp;quot;: false │
│ │ } │
├───────────────────────┼───────────────────────────────────────┤
│ Client TLS Cipher │ │
├───────────────────────┼───────────────────────────────────────┤
│ Connection attributes │ { │
│ │ &amp;quot;_client_name&amp;quot;: &amp;quot;libmariadb&amp;quot;, │
│ │ &amp;quot;_client_version&amp;quot;: &amp;quot;3.3.8&amp;quot;, │
│ │ &amp;quot;_os&amp;quot;: &amp;quot;Linux&amp;quot;, │
│ │ &amp;quot;_pid&amp;quot;: &amp;quot;251037&amp;quot;, │
│ │ &amp;quot;_platform&amp;quot;: &amp;quot;x86_64&amp;quot;, │
│ │ &amp;quot;_server_host&amp;quot;: &amp;quot;10.139.158.211&amp;quot;, │
│ │ &amp;quot;program_name&amp;quot;: &amp;quot;mysql&amp;quot; │
│ │ } │
├───────────────────────┼───────────────────────────────────────┤
│ Connections │ shard1 │
│ │ shard2 │
│ │ shard3 │
├───────────────────────┼───────────────────────────────────────┤
│ Connection IDs │ 666 │
│ │ 139 │
│ │ 138 │
├───────────────────────┼───────────────────────────────────────┤
│ Queries │ │
├───────────────────────┼───────────────────────────────────────┤
│ Log │ │
├───────────────────────┼───────────────────────────────────────┤
│ Memory │ { │
│ │ &amp;quot;connection_buffers&amp;quot;: { │
│ │ &amp;quot;backends&amp;quot;: { │
│ │ &amp;quot;shard1&amp;quot;: { │
│ │ &amp;quot;misc&amp;quot;: 678, │
│ │ &amp;quot;readq&amp;quot;: 65536, │
│ │ &amp;quot;total&amp;quot;: 66214, │
│ │ &amp;quot;writeq&amp;quot;: 0 │
│ │ }, │
│ │ &amp;quot;shard2&amp;quot;: { │
│ │ &amp;quot;misc&amp;quot;: 662, │
│ │ &amp;quot;readq&amp;quot;: 0, │
│ │ &amp;quot;total&amp;quot;: 662, │
│ │ &amp;quot;writeq&amp;quot;: 0 │
│ │ }, │
│ │ &amp;quot;shard3&amp;quot;: { │
│ │ &amp;quot;misc&amp;quot;: 678, │
│ │ &amp;quot;readq&amp;quot;: 65536, │
│ │ &amp;quot;total&amp;quot;: 66214, │
│ │ &amp;quot;writeq&amp;quot;: 0 │
│ │ } │
│ │ }, │
│ │ &amp;quot;client&amp;quot;: { │
│ │ &amp;quot;misc&amp;quot;: 654, │
│ │ &amp;quot;readq&amp;quot;: 65536, │
│ │ &amp;quot;total&amp;quot;: 66190, │
│ │ &amp;quot;writeq&amp;quot;: 0 │
│ │ }, │
│ │ &amp;quot;total&amp;quot;: 199280 │
│ │ }, │
│ │ &amp;quot;exec_metadata&amp;quot;: 0, │
│ │ &amp;quot;last_queries&amp;quot;: 0, │
│ │ &amp;quot;sescmd_history&amp;quot;: 48, │
│ │ &amp;quot;total&amp;quot;: 199328, │
│ │ &amp;quot;variables&amp;quot;: 0 │
│ │ } │
├───────────────────────┼───────────────────────────────────────┤
│ I/O Activity │ 0 │
└───────────────────────┴───────────────────────────────────────┘

shell&amp;gt; maxctrl show listener Sharded-Service-Listener
┌────────────┬───────────────────────────────────────────┐
│ Name │ Sharded-Service-Listener │
├────────────┼───────────────────────────────────────────┤
│ Source │ /etc/maxscale.cnf │
├────────────┼───────────────────────────────────────────┤
│ Service │ Sharded-Service │
├────────────┼───────────────────────────────────────────┤
│ Parameters │ { │
│ │ &amp;quot;MariaDBProtocol&amp;quot;: { │
│ │ &amp;quot;allow_replication&amp;quot;: true │
│ │ }, │
│ │ &amp;quot;address&amp;quot;: &amp;quot;::&amp;quot;, │
│ │ &amp;quot;authenticator&amp;quot;: null, │
│ │ &amp;quot;authenticator_options&amp;quot;: null, │
│ │ &amp;quot;connection_init_sql_file&amp;quot;: null, │
│ │ &amp;quot;connection_metadata&amp;quot;: [ │
│ │ &amp;quot;character_set_client=auto&amp;quot;, │
│ │ &amp;quot;character_set_connection=auto&amp;quot;, │
│ │ &amp;quot;character_set_results=auto&amp;quot;, │
│ │ &amp;quot;max_allowed_packet=auto&amp;quot;, │
│ │ &amp;quot;system_time_zone=auto&amp;quot;, │
│ │ &amp;quot;time_zone=auto&amp;quot;, │
│ │ &amp;quot;tx_isolation=auto&amp;quot; │
│ │ ], │
│ │ &amp;quot;port&amp;quot;: 3306, │
│ │ &amp;quot;protocol&amp;quot;: &amp;quot;MariaDBProtocol&amp;quot;, │
│ │ &amp;quot;proxy_protocol_networks&amp;quot;: null, │
│ │ &amp;quot;service&amp;quot;: &amp;quot;Sharded-Service&amp;quot;, │
│ │ &amp;quot;socket&amp;quot;: null, │
│ │ &amp;quot;sql_mode&amp;quot;: &amp;quot;default&amp;quot;, │
│ │ &amp;quot;ssl&amp;quot;: false, │
│ │ &amp;quot;ssl_ca&amp;quot;: null, │
│ │ &amp;quot;ssl_cert&amp;quot;: null, │
│ │ &amp;quot;ssl_cert_verify_depth&amp;quot;: 9, │
│ │ &amp;quot;ssl_cipher&amp;quot;: null, │
│ │ &amp;quot;ssl_crl&amp;quot;: null, │
│ │ &amp;quot;ssl_key&amp;quot;: null, │
│ │ &amp;quot;ssl_verify_peer_certificate&amp;quot;: false, │
│ │ &amp;quot;ssl_verify_peer_host&amp;quot;: false, │
│ │ &amp;quot;ssl_version&amp;quot;: &amp;quot;MAX&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;listener&amp;quot;, │
│ │ &amp;quot;user_mapping_file&amp;quot;: null │
│ │ } │
└────────────┴───────────────────────────────────────────┘

shell&amp;gt; maxctrl show module schemarouter
┌─────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Module │ schemarouter │
├─────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Type │ Router │
├─────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Version │ V1.0.0 │
├─────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Maturity │ Beta │
├─────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Description │ A database sharding router for simple sharding │
├─────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Parameters │ [ │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: false, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Enable debug mode&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;debug&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;bool&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: [], │
│ │ &amp;quot;description&amp;quot;: &amp;quot;List of tables to ignore when checking for duplicates&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;ignore_tables&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;stringlist&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Regex of tables to ignore when checking for duplicates&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;ignore_tables_regex&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;regex&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: &amp;quot;150000ms&amp;quot;, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Maximum allowed staleness of a database map entry before clients block and wait for an update&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;max_staleness&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;duration&amp;quot;, │
│ │ &amp;quot;unit&amp;quot;: &amp;quot;ms&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: false, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Refresh database mapping information&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;refresh_databases&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;bool&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: &amp;quot;300000ms&amp;quot;, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;How often to refresh the database mapping information&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;refresh_interval&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;duration&amp;quot;, │
│ │ &amp;quot;unit&amp;quot;: &amp;quot;ms&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: false, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Retrieve users from all backend servers instead of only one&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;auth_all_servers&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;bool&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: &amp;quot;300000ms&amp;quot;, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;How ofted idle connections are pinged&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;connection_keepalive&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;duration&amp;quot;, │
│ │ &amp;quot;unit&amp;quot;: &amp;quot;ms&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;deprecated&amp;quot;: true, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Alias for 'wait_timeout'&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;connection_timeout&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;duration&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: false, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Disable session command history&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;disable_sescmd_history&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;bool&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: false, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Allow the root user to connect to this service&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;enable_root_user&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;bool&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: false, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Ping connections unconditionally&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;force_connection_keepalive&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;bool&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: &amp;quot;-1ms&amp;quot;, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Put connections into pool after session has been idle for this long&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;idle_session_pool_time&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;duration&amp;quot;, │
│ │ &amp;quot;unit&amp;quot;: &amp;quot;ms&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: true, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Match localhost to wildcard host&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;localhost_match_wildcard_host&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;bool&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: true, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Log a warning when client authentication fails&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;log_auth_warnings&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;bool&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: false, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Log debug messages for this service (debug builds only)&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;log_debug&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;bool&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: false, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Log info messages for this service&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;log_info&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;bool&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: false, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Log notice messages for this service&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;log_notice&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;bool&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: false, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Log warning messages for this service&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;log_warning&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;bool&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: 0, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Maximum number of connections&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;max_connections&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;count&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: 50, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Session command history size&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;max_sescmd_history&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;count&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: &amp;quot;60000ms&amp;quot;, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;How long a session can wait for a connection to become available&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;multiplex_timeout&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;duration&amp;quot;, │
│ │ &amp;quot;unit&amp;quot;: &amp;quot;ms&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: &amp;quot;0ms&amp;quot;, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Network write timeout&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;net_write_timeout&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;duration&amp;quot;, │
│ │ &amp;quot;unit&amp;quot;: &amp;quot;ms&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Password for the user used to retrieve database users&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: true, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;password&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;password&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: true, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Prune old session command history if the limit is exceeded&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;prune_sescmd_history&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;bool&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: &amp;quot;primary&amp;quot;, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Service rank&amp;quot;, │
│ │ &amp;quot;enum_values&amp;quot;: [ │
│ │ &amp;quot;primary&amp;quot;, │
│ │ &amp;quot;secondary&amp;quot; │
│ │ ], │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;rank&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;enum&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: -1, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Number of statements kept in memory&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;retain_last_statements&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;int&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: false, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Enable session tracing for this service&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;session_trace&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;bool&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: false, │
│ │ &amp;quot;deprecated&amp;quot;: true, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Track session state using server responses&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;session_track_trx_state&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;bool&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: true, │
│ │ &amp;quot;deprecated&amp;quot;: true, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Strip escape characters from database names&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;strip_db_esc&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;bool&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Username used to retrieve database users&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: true, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;user&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Load additional users from a file&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: false, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;user_accounts_file&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;path&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: &amp;quot;add_when_load_ok&amp;quot;, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;When and how the user accounts file is used&amp;quot;, │
│ │ &amp;quot;enum_values&amp;quot;: [ │
│ │ &amp;quot;add_when_load_ok&amp;quot;, │
│ │ &amp;quot;file_only_always&amp;quot; │
│ │ ], │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: false, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;user_accounts_file_usage&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;enum&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Custom version string to use&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;version_string&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;default_value&amp;quot;: &amp;quot;0ms&amp;quot;, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Connection idle timeout&amp;quot;, │
│ │ &amp;quot;mandatory&amp;quot;: false, │
│ │ &amp;quot;modifiable&amp;quot;: true, │
│ │ &amp;quot;name&amp;quot;: &amp;quot;wait_timeout&amp;quot;, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;duration&amp;quot;, │
│ │ &amp;quot;unit&amp;quot;: &amp;quot;ms&amp;quot; │
│ │ } │
│ │ ] │
├─────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Commands │ [ │
│ │ { │
│ │ &amp;quot;attributes&amp;quot;: { │
│ │ &amp;quot;arg_max&amp;quot;: 1, │
│ │ &amp;quot;arg_min&amp;quot;: 1, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Clear schemarouter shard map cache&amp;quot;, │
│ │ &amp;quot;method&amp;quot;: &amp;quot;POST&amp;quot;, │
│ │ &amp;quot;parameters&amp;quot;: [ │
│ │ { │
│ │ &amp;quot;description&amp;quot;: &amp;quot;The schemarouter service&amp;quot;, │
│ │ &amp;quot;required&amp;quot;: true, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;SERVICE&amp;quot; │
│ │ } │
│ │ ] │
│ │ }, │
│ │ &amp;quot;id&amp;quot;: &amp;quot;clear&amp;quot;, │
│ │ &amp;quot;links&amp;quot;: { │
│ │ &amp;quot;self&amp;quot;: &amp;quot;http://127.0.0.1:8989/v1/modules/schemarouter/clear/&amp;quot; │
│ │ }, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;module_command&amp;quot; │
│ │ }, │
│ │ { │
│ │ &amp;quot;attributes&amp;quot;: { │
│ │ &amp;quot;arg_max&amp;quot;: 1, │
│ │ &amp;quot;arg_min&amp;quot;: 1, │
│ │ &amp;quot;description&amp;quot;: &amp;quot;Invalidate schemarouter shard map cache&amp;quot;, │
│ │ &amp;quot;method&amp;quot;: &amp;quot;POST&amp;quot;, │
│ │ &amp;quot;parameters&amp;quot;: [ │
│ │ { │
│ │ &amp;quot;description&amp;quot;: &amp;quot;The schemarouter service&amp;quot;, │
│ │ &amp;quot;required&amp;quot;: true, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;SERVICE&amp;quot; │
│ │ } │
│ │ ] │
│ │ }, │
│ │ &amp;quot;id&amp;quot;: &amp;quot;invalidate&amp;quot;, │
│ │ &amp;quot;links&amp;quot;: { │
│ │ &amp;quot;self&amp;quot;: &amp;quot;http://127.0.0.1:8989/v1/modules/schemarouter/invalidate/&amp;quot; │
│ │ }, │
│ │ &amp;quot;type&amp;quot;: &amp;quot;module_command&amp;quot; │
│ │ } │
│ │ ] │
└─────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

shell&amp;gt; maxctrl show commands schemarouter
┌────────────┬────────────┬──────────────────────────┐
│ Command │ Parameters │ Descriptions │
├────────────┼────────────┼──────────────────────────┤
│ clear │ SERVICE │ The schemarouter service │
├────────────┼────────────┼──────────────────────────┤
│ invalidate │ SERVICE │ The schemarouter service │
└────────────┴────────────┴──────────────────────────┘

shell&amp;gt; maxctrl show dbusers Sharded-Service
┌───────────────────────┬────────────────┬───────────────────────┬───────┬───────┬────────┬───────┬──────┐
│ User │ Host │ Plugin │ TLS │ Super │ Global │ Proxy │ Role │
├───────────────────────┼────────────────┼───────────────────────┼───────┼───────┼────────┼───────┼──────┤
│ PUBLIC │ │ │ false │ false │ false │ false │ │
├───────────────────────┼────────────────┼───────────────────────┼───────┼───────┼────────┼───────┼──────┤
│ app │ 10.139.158.% │ mysql_native_password │ false │ false │ false │ false │ │
├───────────────────────┼────────────────┼───────────────────────┼───────┼───────┼────────┼───────┼──────┤
│ app_role │ │ │ false │ false │ false │ false │ │
├───────────────────────┼────────────────┼───────────────────────┼───────┼───────┼────────┼───────┼──────┤
│ mariadb.sys │ localhost │ mysql_native_password │ false │ false │ false │ false │ │
├───────────────────────┼────────────────┼───────────────────────┼───────┼───────┼────────┼───────┼──────┤
│ maxscale_admin │ 10.139.158.210 │ mysql_native_password │ false │ false │ false │ false │ │
├───────────────────────┼────────────────┼───────────────────────┼───────┼───────┼────────┼───────┼──────┤
│ maxscale_admin │ 10.139.158.211 │ mysql_native_password │ false │ false │ false │ false │ │
├───────────────────────┼────────────────┼───────────────────────┼───────┼───────┼────────┼───────┼──────┤
│ maxscale_admin_role │ │ │ false │ false │ false │ false │ │
├───────────────────────┼────────────────┼───────────────────────┼───────┼───────┼────────┼───────┼──────┤
│ maxscale_monitor │ 10.139.158.210 │ mysql_native_password │ false │ false │ false │ false │ │
├───────────────────────┼────────────────┼───────────────────────┼───────┼───────┼────────┼───────┼──────┤
│ maxscale_monitor │ 10.139.158.211 │ mysql_native_password │ false │ false │ false │ false │ │
├───────────────────────┼────────────────┼───────────────────────┼───────┼───────┼────────┼───────┼──────┤
│ maxscale_monitor_role │ │ │ false │ false │ false │ false │ │
├───────────────────────┼────────────────┼───────────────────────┼───────┼───────┼────────┼───────┼──────┤
│ mysql │ localhost │ mysql_native_password │ false │ true │ true │ false │ │
├───────────────────────┼────────────────┼───────────────────────┼───────┼───────┼────────┼───────┼──────┤
│ root │ localhost │ mysql_native_password │ false │ true │ true │ false │ │
└───────────────────────┴────────────────┴───────────────────────┴───────┴───────┴────────┴───────┴──────┘

shell&amp;gt; maxctrl show commands mariadbmon
┌───────────────────────────┬─────────────────────────────┬───────────────────────────────────────────────────────────────────────────────┐
│ Command │ Parameters │ Descriptions │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ switchover │ MONITOR, [SERVER], [SERVER] │ Monitor name, New primary (optional), Current primary (optional) │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ switchover-force │ MONITOR, [SERVER], [SERVER] │ Monitor name, New primary (optional), Current primary (optional) │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ async-switchover │ MONITOR, [SERVER], [SERVER] │ Monitor name, New primary (optional), Current primary (optional) │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ failover │ MONITOR │ Monitor name │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ async-failover │ MONITOR │ Monitor name │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ rejoin │ MONITOR, SERVER │ Monitor name, Joining server │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ async-rejoin │ MONITOR, SERVER │ Monitor name, Joining server │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ reset-replication │ MONITOR, [SERVER] │ Monitor name, Primary server (optional) │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ async-reset-replication │ MONITOR, [SERVER] │ Monitor name, Primary server (optional) │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ release-locks │ MONITOR │ Monitor name │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ async-release-locks │ MONITOR │ Monitor name │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ fetch-cmd-result │ MONITOR │ Monitor name │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ cancel-cmd │ MONITOR │ Monitor name │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ async-cs-add-node │ MONITOR, STRING, STRING │ Monitor name, Hostname/IP of node to add to ColumnStore cluster, Timeout │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ async-cs-remove-node │ MONITOR, STRING, STRING │ Monitor name, Hostname/IP of node to remove from ColumnStore cluster, Timeout │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ cs-get-status │ MONITOR │ Monitor name │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ async-cs-get-status │ MONITOR │ Monitor name │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ async-cs-start-cluster │ MONITOR, STRING │ Monitor name, Timeout │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ async-cs-stop-cluster │ MONITOR, STRING │ Monitor name, Timeout │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ async-cs-set-readonly │ MONITOR, STRING │ Monitor name, Timeout │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ async-cs-set-readwrite │ MONITOR, STRING │ Monitor name, Timeout │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ async-rebuild-server │ MONITOR, SERVER, [SERVER] │ Monitor name, Target server, Source server (optional) │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ async-create-backup │ MONITOR, SERVER, STRING │ Monitor name, Source server, Backup name │
├───────────────────────────┼─────────────────────────────┼───────────────────────────────────────────────────────────────────────────────┤
│ async-restore-from-backup │ MONITOR, SERVER, STRING │ Monitor name, Target server, Backup name │
└───────────────────────────┴─────────────────────────────┴───────────────────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="literature--sources"&gt;Literature / Sources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;MaxScale: &lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-simple-sharding-with-two-servers/" target="_blank"&gt;Simple Sharding with Two Servers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;MaxScale: &lt;a href="https://mariadb.com/kb/en/mariadb-maxscale-2308-schemarouter/" target="_blank"&gt;SchemaRouter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>dbstat for MariaDB (and MySQL)</title><link>https://www.fromdual.com/blog/dbstat-for-mariadb-and-mysql/</link><pubDate>Thu, 14 Mar 2024 15:36:57 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/dbstat-for-mariadb-and-mysql/</guid><description>&lt;h2 id="table-of-contents"&gt;Table of contents&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-and-mysql/#features"&gt;Functionality of &lt;code&gt;dbstat&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-and-mysql/#how-does-dbstat-work"&gt;How does &lt;code&gt;dbstat&lt;/code&gt; work&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-and-mysql/#installation"&gt;How to install &lt;code&gt;dbstat&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-and-mysql/#queries"&gt;Query &lt;code&gt;dbstat&lt;/code&gt;&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-and-mysql/#table_size"&gt;&lt;code&gt;table_size&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-and-mysql/#processlist"&gt;&lt;code&gt;processlist&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-and-mysql/#trx_and_lck"&gt;&lt;code&gt;trx_and_lck&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-and-mysql/#metadata_lock"&gt;&lt;code&gt;metadata_lock&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-and-mysql/#global_variables"&gt;&lt;code&gt;global_variables&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-and-mysql/#global_status"&gt;&lt;code&gt;global_status&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-and-mysql/#testing"&gt;Testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/blog/dbstat-for-mariadb-and-mysql/#sources"&gt;Sources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An idea that I have been thinking about for a long time and have now, thanks to a customer, finally tackled is &lt;code&gt;dbstat&lt;/code&gt; for MariaDB/MySQL. The idea is based on &lt;code&gt;sar/sysstat&lt;/code&gt; by Sebastien Godard:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;sar - Collect, report, or save system activity information.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and &lt;a href="https://docs.oracle.com/cd/A97385_01/server.920/a96533/statspac.htm" target="_blank"&gt;Oracle Statspack&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Statspack is a performance tuning tool &amp;hellip; to quickly gather detailed analysis of the performance of that database instance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="functionality-of-dbstat"&gt;Functionality of &lt;code&gt;dbstat&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Although we have had the performance schema for some time, it does not cover some points that we see as a problem in practice and that are requested by customers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;table_size&lt;/code&gt; module collects data on the growth of tables. This allows statements to be made about the growth of individual tables, databases, future &lt;a href="https://mariadb.com/kb/en/catalogs/" target="_blank"&gt;MariaDB Catalogs&lt;/a&gt; or the entire instance. This is interesting for users who are using multi-tenant systems or are otherwise struggling with uncontrolled growth.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;processlist&lt;/code&gt; module takes a snapshot of the process list at regular intervals and saves it. This information is useful for post-mortem analyses if the user was too slow to save his process list or to understand how a problem has built up.&lt;/li&gt;
&lt;li&gt;The problem is often caused by long-running transactions, row locks or metadata locks. These are recorded and saved by the &lt;code&gt;trx_and_lck&lt;/code&gt; and &lt;code&gt;metadata_lock&lt;/code&gt; modules. This means that we can see problems that we did not even notice before or we can see what led to the problem after the accident (analogous to a tachograph in a vehicle).&lt;/li&gt;
&lt;li&gt;Another question that we sometimes encounter in practice is: When was which database variable changed and what did it look like before? This is covered by the &lt;code&gt;global_variables&lt;/code&gt; module. Unfortunately, it is not possible to find out who changed the variable or why. Operational processes are required for this.&lt;/li&gt;
&lt;li&gt;The last module, &lt;code&gt;global_status&lt;/code&gt;, actually covers what &lt;code&gt;sar/sysstat does&lt;/code&gt;. It collects the values from &lt;code&gt;SHOW GLOBAL STATUS;&lt;/code&gt; and saves them for later analysis purposes or to simply create graphs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-does-dbstat-work"&gt;How does &lt;code&gt;dbstat&lt;/code&gt; work&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;dbstat&lt;/code&gt; uses the database &lt;a href="https://mariadb.com/kb/en/event-scheduler/" target="_blank"&gt;Event Scheduler&lt;/a&gt; as a scheduler. This must first be switched on for MariaDB (&lt;code&gt;event_scheduler = ON&lt;/code&gt;). With MySQL it is already switched on by default. The Event Scheduler has the advantage that we can activate the jobs at a finer granularity, for example 10 s, which would not be possible with the crontab.&lt;/p&gt;
&lt;p&gt;The Event Scheduler then executes &lt;a href="https://mariadb.com/kb/en/create-procedure/" target="_blank"&gt;SQL/PSM&lt;/a&gt; code to collect the data on the one hand and to delete the data on the other, so that the &lt;code&gt;dbstat&lt;/code&gt; database does not grow immeasurably.&lt;/p&gt;
&lt;p&gt;The following jobs are currently planned:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;Collect&lt;/th&gt;
&lt;th&gt;Delete&lt;/th&gt;
&lt;th&gt;Quantity structure&lt;/th&gt;
&lt;th&gt;Remarks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;table_size&lt;/td&gt;
&lt;td&gt;1/d at 02:04&lt;/td&gt;
&lt;td&gt;12/h, 1000 rows, &amp;gt; 31 d&lt;/td&gt;
&lt;td&gt;1000 tab × 31 d = 31k rows&lt;/td&gt;
&lt;td&gt;Should work up to 288k tables.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;processlist&lt;/td&gt;
&lt;td&gt;1/min&lt;/td&gt;
&lt;td&gt;1/min, 1000 rows, &amp;gt; 7 d&lt;/td&gt;
&lt;td&gt;1000 con × 1440 min × 7 d = 10M rows&lt;/td&gt;
&lt;td&gt;Should work up to 1000 concurrent connections.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;trx_and_lck&lt;/td&gt;
&lt;td&gt;1/min&lt;/td&gt;
&lt;td&gt;1/min, 1000 rows, &amp;gt; 7 d&lt;/td&gt;
&lt;td&gt;100 lck × 1440 min × 7 d = 1M rows&lt;/td&gt;
&lt;td&gt;Depends very much on the application.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;metadata_lock&lt;/td&gt;
&lt;td&gt;1/min&lt;/td&gt;
&lt;td&gt;12/h, 1000 rows, &amp;gt; 30 d&lt;/td&gt;
&lt;td&gt;100 mdl × 1440 × 30 d = 4M rows&lt;/td&gt;
&lt;td&gt;Depends very much on the application.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;global_variables&lt;/td&gt;
&lt;td&gt;1/min&lt;/td&gt;
&lt;td&gt;never&lt;/td&gt;
&lt;td&gt;1000 rows&lt;/td&gt;
&lt;td&gt;Normally this table should not grow.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;global_status&lt;/td&gt;
&lt;td&gt;1/min&lt;/td&gt;
&lt;td&gt;1/min, 1000 rows, &amp;gt; 30 d&lt;/td&gt;
&lt;td&gt;1000 rows × 1440 × 30 d = 40M&lt;/td&gt;
&lt;td&gt;Rows can become large?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="how-to-install-dbstat"&gt;How to install &lt;code&gt;dbstat&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;dbstat&lt;/code&gt; can be downloaded from &lt;a href="https://github.com/FromDual/dbstat" target="_blank"&gt;Github&lt;/a&gt; and is licensed under GPLv2.&lt;/p&gt;
&lt;p&gt;The installation is simple: First execute the SQL file &lt;code&gt;create_user_and_db.sql&lt;/code&gt;. Then execute the corresponding &lt;code&gt;create_*.sql&lt;/code&gt; files for the respective modules in the &lt;code&gt;dbstat&lt;/code&gt; database. There are currently no direct dependencies between the modules. If you want to use a different user or a different database than dbstat, you have to take care of this yourself.&lt;/p&gt;
&lt;h2 id="query-dbstat"&gt;Query &lt;code&gt;dbstat&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Some possible queries on the data have already been prepared. They can be found in the &lt;code&gt;query_*.sql&lt;/code&gt; files. Here are a few examples:&lt;/p&gt;
&lt;p&gt;table_size&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT `table_schema`, `table_name`, `ts`, `table_rows`, `data_length`, `index_length`
 FROM `table_size`
 WHERE `table_catalog` = 'def'
 AND `table_schema` = 'dbstat'
 AND `table_name` = 'table_size'
ORDER BY `ts` ASC
;
+--------------+------------+---------------------+------------+-------------+--------------+
| table_schema | table_name | ts | table_rows | data_length | index_length |
+--------------+------------+---------------------+------------+-------------+--------------+
| dbstat | table_size | 2024-03-09 20:01:00 | 0 | 16384 | 16384 |
| dbstat | table_size | 2024-03-10 17:26:33 | 310 | 65536 | 16384 |
| dbstat | table_size | 2024-03-11 08:28:12 | 622 | 114688 | 49152 |
| dbstat | table_size | 2024-03-12 08:02:38 | 934 | 114688 | 49152 |
| dbstat | table_size | 2024-03-13 08:08:55 | 1247 | 278528 | 81920 |
+--------------+------------+---------------------+------------+-------------+--------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="processlist"&gt;processlist&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;SELECT connection_id, ts, time, state, SUBSTR(REGEXP_REPLACE(REPLACE(query, &amp;quot;&amp;lt;br&amp;gt;n&amp;quot;, ' '), '&amp;lt;br&amp;gt; +', ' '), 1, 64) AS query
 FROM processlist
 WHERE command != 'Sleep'
 AND connection_id = @connection_id
 ORDER BY ts ASC
 LIMIT 5
;
+---------------+---------------------+---------+---------------------------------+---------------------------------------------+
| connection_id | ts | time | state | query |
+---------------+---------------------+---------+---------------------------------+---------------------------------------------+
| 14956 | 2024-03-09 20:21:12 | 13.042 | Waiting for table metadata lock | update test set data = 'bla' where id = 100 |
| 14956 | 2024-03-09 20:22:12 | 73.045 | Waiting for table metadata lock | update test set data = 'bla' where id = 100 |
| 14956 | 2024-03-09 20:23:12 | 133.044 | Waiting for table metadata lock | update test set data = 'bla' where id = 100 |
| 14956 | 2024-03-09 20:24:12 | 193.044 | Waiting for table metadata lock | update test set data = 'bla' where id = 100 |
| 14956 | 2024-03-09 20:25:12 | 253.041 | Waiting for table metadata lock | update test set data = 'bla' where id = 100 |
+---------------+---------------------+---------+---------------------------------+---------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="trx_and_lck"&gt;trx_and_lck&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;SELECT * FROM trx_and_lck&amp;lt;br&amp;gt;G
*************************** 1. row ***************************
 machine_name:
 connection_id: 14815
 trx_id: 269766
 ts: 2024-03-09 20:05:57
 user: root
 host: localhost
 db: test
 command: Query
 time: 41.000
 running_since: 2024-03-09 20:05:16
 state: Statistics
 info: select * from test where id = 6 for update
 trx_state: LOCK WAIT
 trx_started: 2024-03-09 20:05:15
trx_requested_lock_id: 269766:821:5:7
 trx_tables_in_use: 1
 trx_tables_locked: 1
 trx_lock_structs: 2
 trx_rows_locked: 1
 trx_rows_modified: 0
 lock_mode: X
 lock_type: RECORD
 lock_table_schema: test
 lock_table_name: test
 lock_index: PRIMARY
 lock_space: 821
 lock_page: 5
 lock_rec: 7
 lock_data: 6
*************************** 2. row ***************************
 machine_name:
 connection_id: 14817
 trx_id: 269760
 ts: 2024-03-09 20:05:57
 user: root
 host: localhost
 db: test
 command: Sleep
 time: 60.000
 running_since: 2024-03-09 20:04:57
 state:
 info:
 trx_state: RUNNING
 trx_started: 2024-03-09 20:04:56
trx_requested_lock_id: NULL
 trx_tables_in_use: 0
 trx_tables_locked: 1
 trx_lock_structs: 2
 trx_rows_locked: 1
 trx_rows_modified: 1
 lock_mode: X
 lock_type: RECORD
 lock_table_schema: test
 lock_table_name: test
 lock_index: PRIMARY
 lock_space: 821
 lock_page: 5
 lock_rec: 7
 lock_data: 6
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="metadata_lock"&gt;metadata_lock&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;SELECT lock_mode, ts, user, host, lock_type, table_schema, table_name, time, started, state, query
 FROM metadata_lock
 WHERE connection_id = 14347
 ORDER BY started DESC
 LIMIT 5
;
+-------------------------+---------------------+------+-----------+----------------------+--------------+------------+-------+---------------------+----------------+------------------------------------------------------+
| lock_mode | ts | user | host | lock_type | table_schema | table_name | time | started | state | query |
+-------------------------+---------------------+------+-----------+----------------------+--------------+------------+-------+---------------------+----------------+------------------------------------------------------+
| MDL_SHARED_WRITE | 2024-03-13 10:27:33 | root | localhost | Table metadata lock | test | test | 1.000 | 2024-03-13 10:27:32 | Updating | UPDATE test set data3 = MD5(id) |
| MDL_BACKUP_TRANS_DML | 2024-03-13 10:27:33 | root | localhost | Backup lock | | | 1.000 | 2024-03-13 10:27:32 | Updating | UPDATE test set data3 = MD5(id) |
| MDL_BACKUP_ALTER_COPY | 2024-03-13 10:22:33 | root | localhost | Backup lock | | | 0.000 | 2024-03-13 10:22:33 | altering table | ALTER TABLE test DROP INDEX ts, ADD INDEX (ts, data) |
| MDL_SHARED_UPGRADABLE | 2024-03-13 10:22:33 | root | localhost | Table metadata lock | test | test | 0.000 | 2024-03-13 10:22:33 | altering table | ALTER TABLE test DROP INDEX ts, ADD INDEX (ts, data) |
| MDL_INTENTION_EXCLUSIVE | 2024-03-13 10:22:33 | root | localhost | Schema metadata lock | test | | 0.000 | 2024-03-13 10:22:33 | altering table | ALTER TABLE test DROP INDEX ts, ADD INDEX (ts, data) |
+-------------------------+---------------------+------+-----------+----------------------+--------------+------------+-------+---------------------+----------------+------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="global_variables"&gt;global_variables&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;SELECT variable_name, COUNT(*) AS cnt
 FROM global_variables
 GROUP BY variable_name
 HAVING COUNT(*) &amp;gt; 1
;
+-------------------------+-----+
| variable_name | cnt |
+-------------------------+-----+
| innodb_buffer_pool_size | 7 |
+-------------------------+-----+

SELECT variable_name, ts, variable_value
 FROM global_variables
 WHERE variable_name = 'innodb_buffer_pool_size'
;
+-------------------------+---------------------+----------------+
| variable_name | ts | variable_value |
+-------------------------+---------------------+----------------+
| innodb_buffer_pool_size | 2024-03-09 21:36:28 | 134217728 |
| innodb_buffer_pool_size | 2024-03-09 21:40:25 | 268435456 |
| innodb_buffer_pool_size | 2024-03-09 21:48:14 | 134217728 |
+-------------------------+---------------------+----------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="global_status"&gt;global_status&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;SELECT s1.ts
 , s1.variable_value AS 'table_open_cache_misses'
 , s2.variable_value AS 'table_open_cache_hits'
 FROM global_status AS s1
 JOIN global_status AS s2 ON s1.ts = s2.ts
 WHERE s1.variable_name = 'table_open_cache_misses'
 AND s2.variable_name = 'table_open_cache_hits'
 AND s1.ts BETWEEN '2024-03-13 11:55:00' AND '2024-03-13 12:05:00'
 ORDER BY ts ASC
;
+---------------------+-------------------------+-----------------------+
| ts | table_open_cache_misses | table_open_cache_hits |
+---------------------+-------------------------+-----------------------+
| 2024-03-13 11:55:47 | 1001 | 60711 |
| 2024-03-13 11:56:47 | 1008 | 61418 |
| 2024-03-13 11:57:47 | 1015 | 62125 |
| 2024-03-13 11:58:47 | 1022 | 62829 |
| 2024-03-13 11:59:47 | 1029 | 63533 |
| 2024-03-13 12:00:47 | 1036 | 64237 |
| 2024-03-13 12:01:47 | 1043 | 64944 |
| 2024-03-13 12:02:47 | 1050 | 65651 |
| 2024-03-13 12:03:47 | 1057 | 66355 |
| 2024-03-13 12:04:47 | 1064 | 67059 |
+---------------------+-------------------------+-----------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="testing"&gt;Testing&lt;/h3&gt;
&lt;p&gt;We have currently rolled out &lt;code&gt;dbstat&lt;/code&gt; on our test and production systems to test it and see whether our assumptions regarding stability and calculations of the quantity structure are correct. In addition, using it ourselves is the best way to find out if something is missing or if the handling is impractical (&lt;a href="https://en.wikipedia.org/wiki/Eating_your_own_dog_food" target="_blank"&gt;Eat your own dog food&lt;/a&gt;).&lt;/p&gt;
&lt;h3 id="sources"&gt;Sources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://linux.die.net/man/1/sar" target="_blank"&gt;&lt;code&gt;sar&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/cd/A97385_01/server.920/a96533/statspac.htm" target="_blank"&gt;Using Oracle Statspack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/FromDual/dbstat" target="_blank"&gt;&lt;code&gt;dbstat&lt;/code&gt; on Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/SQL/PSM" target="_blank"&gt;SQL/PSM&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>MariaDB/MySQL Environment MyEnv 2.1.0 has been released</title><link>https://www.fromdual.com/blog/myenv-release-notes/fromdual-environment-myenv-2.1.0-has-been-released/</link><pubDate>Wed, 28 Feb 2024 17:22:29 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/myenv-release-notes/fromdual-environment-myenv-2.1.0-has-been-released/</guid><description>&lt;p&gt;FromDual has the pleasure to announce the release of the new version 2.1.0 of its popular MariaDB, Galera Cluster and MySQL multi-instance environment &lt;a href="https://www.fromdual.com/myenv-mysql-mariadb-basenv" title="MariaDB/MySQL multi-instance environment"&gt;MyEnv&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The new MyEnv can be downloaded &lt;a href="https://www.fromdual.com/download" title="FromDual download"&gt;here&lt;/a&gt;. How to install MyEnv is described in the &lt;a href="https://www.fromdual.com/myenv-installation-guide" title="MyEnv Installation Guide"&gt;MyEnv Installation Guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the inconceivable case that you find a bug in the MyEnv please report it to the FromDual &lt;a href="https://support.fromdual.com/bugs/login_page.php" target="_blank" title="FromDual bug tracker"&gt;bug tracker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Any feedback, statements and testimonials are welcome as well! Please send them to [feedback@fromdual.com](mailto:feedback@fromdual.com?Subject=Feedback for MyEnv).&lt;/p&gt;
&lt;h2 id="upgrade-from-11x-to-20"&gt;Upgrade from 1.1.x to 2.0&lt;/h2&gt;
&lt;p&gt;Please look at the &lt;a href="https://www.fromdual.com/mysql-mariadb-environment-myenv-2.0.0-has-been-released" title="MySQL Environment MyEnv 2.0.0 has been released"&gt;MyEnv 2.0.0 Release Notes&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="upgrade-from-20x-to-210"&gt;Upgrade from 2.0.x to 2.1.0&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; cd ${HOME}/product
shell&amp;gt; tar xf /download/myenv-2.1.0.tar.gz
shell&amp;gt; rm -f myenv
shell&amp;gt; ln -s myenv-2.1.0 myenv
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="plug-ins"&gt;Plug-ins&lt;/h3&gt;
&lt;p&gt;If you are using plug-ins for &lt;code&gt;showMyEnvStatus&lt;/code&gt; create all the links in the new directory structure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; cd ${HOME}/product/myenv
shell&amp;gt; ln -s ../../utl/oem_agent.php plg/showMyEnvStatus/
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="upgrade-of-the-instance-directory-structure"&gt;Upgrade of the instance directory structure&lt;/h3&gt;
&lt;p&gt;From MyEnv 1.0 to 2.0 the directory structure of instances has fundamentally changed. Nevertheless MyEnv 2.0 works fine with MyEnv 1.0 directory structures.&lt;/p&gt;
&lt;h2 id="changes-in-myenv-210"&gt;Changes in MyEnv 2.1.0&lt;/h2&gt;
&lt;h3 id="myenv"&gt;MyEnv&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Removed hard coded parts for running MyEnv under O/S user &lt;code&gt;mariadb&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;substitute_path&lt;/code&gt; was refactored.&lt;/li&gt;
&lt;li&gt;Branch guessing improved.&lt;/li&gt;
&lt;li&gt;Warnings and errors are in color now.&lt;/li&gt;
&lt;li&gt;MyEnv log file is now touched to avoid problems with O/S user &lt;code&gt;root&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;O/S user
mysql
removed in start/stop script.&lt;/li&gt;
&lt;li&gt;Checks for DB start improved.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/var/run&lt;/code&gt; replaced by the more modern location &lt;code&gt;/run&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Should now be completely MariaDB compatible (&lt;code&gt;mariadbd&lt;/code&gt; vs. &lt;code&gt;mysqld&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Wrapper &lt;code&gt;mysqld_safe&lt;/code&gt; was extended to &lt;code&gt;mariadbd-safe&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Replaced &lt;code&gt;getVersionFromMysqld&lt;/code&gt; by &lt;code&gt;getVersionAndBranchFromDaemon&lt;/code&gt; and extended functionality of this function.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt; was set to the wrong directory.&lt;/li&gt;
&lt;li&gt;Reverting Commit: fcc93c5 from v2.0.3 related to &lt;code&gt;CDPATH&lt;/code&gt;. Break commands like &lt;code&gt;cd log&lt;/code&gt; or &lt;code&gt;cd etc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Database &lt;code&gt;mysql_innodb_cluster_metadata&lt;/code&gt; is hidden now.&lt;/li&gt;
&lt;li&gt;Database &lt;code&gt;#innodb_redo&lt;/code&gt; is suppressed now as well for MySQL 8.0, and &lt;code&gt;hideschema&lt;/code&gt; is not added to every new instance any more to not overwrite the default.&lt;/li&gt;
&lt;li&gt;Bug while stopping instance with missing &lt;code&gt;my.cnf&lt;/code&gt; fixed.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;getDistribution&lt;/code&gt; cleaned-up.&lt;/li&gt;
&lt;li&gt;MySQL should now also be detected correctly from Ubuntu repository.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;my_exec&lt;/code&gt; rewritten.&lt;/li&gt;
&lt;li&gt;Debian GNU/Linux tag added for distros.&lt;/li&gt;
&lt;li&gt;Function &lt;code&gt;extractBranch&lt;/code&gt; made better to work on Debian and Ubuntu with distribution packages.&lt;/li&gt;
&lt;li&gt;Oracle Linux is considered as well now.&lt;/li&gt;
&lt;li&gt;Made scripts ready for new MariaDB behaviour.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;my.cnf&lt;/code&gt; template adapted to newest knowledge.&lt;/li&gt;
&lt;li&gt;Directory changed from &lt;code&gt;/tmp&lt;/code&gt; to &lt;code&gt;/var/tmp&lt;/code&gt;, code cleaned-up and renewal, PID file code and message improved in &lt;code&gt;stopInstance&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Distributions cleaned-up and cloudlinux, rocky linux and almalinux added as centos compatible distros.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="myenv-installer"&gt;MyEnv Installer&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Debian 10 and 11 do not support PHP 8.0 yet, fixed.&lt;/li&gt;
&lt;li&gt;Unit file is copied now correctly.&lt;/li&gt;
&lt;li&gt;MyEnv instance installation is automatizable now.&lt;/li&gt;
&lt;li&gt;Instance creation automation added.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;my.cnf&lt;/code&gt; template together with &lt;code&gt;installMyenv&lt;/code&gt; should now work without errors or warnings for MariaDB 10.5 - 11.2 and MySQL 8.0 - 8.3.&lt;/li&gt;
&lt;li&gt;Command &lt;code&gt;yum&lt;/code&gt; replaced by &lt;code&gt;dnf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Command &lt;code&gt;apt-get&lt;/code&gt; comments replaced by &lt;code&gt;apt&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="myenv-utilities"&gt;MyEnv Utilities&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Client utility adapted in &lt;code&gt;*monitor&lt;/code&gt; scripts.&lt;/li&gt;
&lt;li&gt;InnoDB cluster monitor added.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wsrep_last_committed&lt;/code&gt; was added in &lt;code&gt;galera_monitor.sh&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;AWR added, sharding stuff added, lock and trx analysis scripts added.&lt;/li&gt;
&lt;li&gt;Memory analysis added, NUMA maps output made ready for new variables.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;connect_maxout&lt;/code&gt; utility added.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For subscriptions of commercial use of MyEnv please [get in contact](mailto:contact@fromdual.com?Subject=Commercial use of MyEnv) with us.&lt;/p&gt;</description></item><item><title>MyEnv Release Notes</title><link>https://www.fromdual.com/blog/myenv-release-notes/</link><pubDate>Wed, 28 Feb 2024 16:51:26 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/myenv-release-notes/</guid><description>&lt;ul&gt;
&lt;li&gt;MyEnv 3.0.0 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/fromdual-environment-myenv-3.0.0-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 23 March 2026&lt;/li&gt;
&lt;li&gt;MyEnv 2.1.1 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/fromdual-environment-myenv-2.1.1-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 12 December 2025&lt;/li&gt;
&lt;li&gt;MyEnv 2.1.0 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/fromdual-environment-myenv-2.1.0-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 28 February 2024&lt;/li&gt;
&lt;li&gt;MyEnv 2.0.3 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mariadb-mysql-environment-myenv-2.0.3-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 2 July 2021&lt;/li&gt;
&lt;li&gt;MyEnv 2.0.2 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mariadb-mysql-environment-myenv-2.0.2-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 17 January 2019&lt;/li&gt;
&lt;li&gt;MyEnv 2.0.1 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mariadb-mysql-environment-myenv-2.0.1-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 3 October 2018&lt;/li&gt;
&lt;li&gt;MyEnv 2.0.0 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mariadb-mysql-environment-myenv-2.0.0-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 15 March 2018&lt;/li&gt;
&lt;li&gt;MyEnv 1.3.1 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mysql-environment-myenv-1.3.1-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 3 August 2016&lt;/li&gt;
&lt;li&gt;MyEnv 1.3.0 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mysql-environment-myenv-1.3.0-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 31 January 2016&lt;/li&gt;
&lt;li&gt;MyEnv 1.2.2 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mysql-environment-myenv-1.2.2-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 12 October 2015&lt;/li&gt;
&lt;li&gt;MyEnv 1.2.1 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mysql-environment-myenv-1.2.1-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 27 July 2015&lt;/li&gt;
&lt;li&gt;MyEnv 1.2.0 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mysql-environment-myenv-1.2.0-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 18 April 2015&lt;/li&gt;
&lt;li&gt;MyEnv 1.1.4 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mysql-environment-myenv-1.1.4-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 11 February 2015&lt;/li&gt;
&lt;li&gt;MyEnv 1.1.3 Release Notes: Skipped, see v1.1.4, Release Date: 30 January 2015&lt;/li&gt;
&lt;li&gt;MyEnv 1.1.2 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mysql-environment-myenv-1.1.2-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 23 October 2014&lt;/li&gt;
&lt;li&gt;MyEnv 1.1.1 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mysql-environment-myenv-1.1.1-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 8 September 2014&lt;/li&gt;
&lt;li&gt;MyEnv 1.1.0 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mysql-environment-myenv-1.1.0-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 23 August 2014&lt;/li&gt;
&lt;li&gt;MyEnv 1.0.5 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mysql-environment-myenv-1.0.5-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 13 June 2014&lt;/li&gt;
&lt;li&gt;MyEnv 1.0.4 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mysql-environment-myenv-1.0.4-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 29 April 2014&lt;/li&gt;
&lt;li&gt;MyEnv 1.0.3 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mysql-environment-myenv-1.0.3-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 25 April 2014&lt;/li&gt;
&lt;li&gt;MyEnv 1.0.2 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mysql-environment-myenv-1.0.2-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 11 December 2013&lt;/li&gt;
&lt;li&gt;MyEnv 1.0.1 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mysql-environment-myenv-1.0.1-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 5 November 2013&lt;/li&gt;
&lt;li&gt;MyEnv 1.0 &lt;a href="https://www.fromdual.com/blog/myenv-release-notes/mysql-environment-myenv-1.0-has-been-released/"&gt;Release Notes&lt;/a&gt;, Release Date: 4 October 2013&lt;/li&gt;
&lt;li&gt;MyEnv 0.4 Release notes: none, Release Date: 30 March 2011&lt;/li&gt;
&lt;li&gt;MyEnv 0.3.6 Release notes: none, Release Date: 23 January 2011&lt;/li&gt;
&lt;li&gt;MyEnv 0.3.5 Release notes: none, Release Date: 22 January 2011&lt;/li&gt;
&lt;li&gt;MyEnv 0.3.4 Release notes: none, Release Date: 21 November 2010&lt;/li&gt;
&lt;li&gt;MyEnv 0.3.3 Release notes: none, Release Date: 21 November 2010&lt;/li&gt;
&lt;li&gt;MyEnv 0.3.2 Release notes: none, Release Date: 14 November 2010&lt;/li&gt;
&lt;li&gt;MyEnv 0.3.1 Release notes: none, Release Date: 14 November 2010&lt;/li&gt;
&lt;li&gt;MyEnv 0.3 Release notes: none, Release Date: 13 November 2010&lt;/li&gt;
&lt;li&gt;MyEnv 0.2.7 Release notes: none, Release Date: 12 August 2010&lt;/li&gt;
&lt;li&gt;MyEnv 0.2.6 Release notes: none, Release Date: 12 August 2010&lt;/li&gt;
&lt;li&gt;MyEnv 0.2.5 Release notes: none, Release Date: 12 August 2010&lt;/li&gt;
&lt;li&gt;MyEnv 0.2.4 Release notes: none, Release Date: 12 August 2010&lt;/li&gt;
&lt;li&gt;MyEnv 0.2.3 Release notes: none, Release Date: 19 January 2010&lt;/li&gt;
&lt;li&gt;MyEnv 0.2.2 Release notes: none, Release Date: 7 January 2010&lt;/li&gt;
&lt;li&gt;MyEnv 0.2.1 Release notes: none, Release Date: 31 December 2009&lt;/li&gt;
&lt;li&gt;MyEnv 0.2 Release notes: none, Release Date: 24 December 2009&lt;/li&gt;
&lt;li&gt;MyEnv 0.1.1 Release notes: none, Release Date: 18 July 2008&lt;/li&gt;
&lt;li&gt;MyEnv 0.1 Release notes: none, Release Date: 18 July 2008&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>We build a data warehouse from the General Query Log</title><link>https://www.fromdual.com/blog/we-build-a-data-warehouse-from-the-general-query-log/</link><pubDate>Wed, 31 Jan 2024 16:41:13 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/we-build-a-data-warehouse-from-the-general-query-log/</guid><description>&lt;p&gt;The design of a data warehouse differs from relational design. Data warehouses are often designed according to the concept of the &lt;a href="https://en.wikipedia.org/wiki/Star_schema" target="_blank" title="Star Schema on Wikipedia"&gt;star schema&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When building a data warehouse, you usually put the cart before the horse:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What questions should my data warehouse be able to answer?&lt;/li&gt;
&lt;li&gt;How do I have to design my model so that my questions can be answered easily?&lt;/li&gt;
&lt;li&gt;Where do I get the data to populate the model?&lt;/li&gt;
&lt;li&gt;How do I fill my model with the data?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For training purposes, we have investigated an issue that arises from time to time with our support team: The system suddenly and unexpectedly starts to behave unusually, nobody has done anything and nobody knows why. Example with a customer last week: The system starts to become unstable at 3 pm, is then restarted hard and then stabilises again from 4 pm&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.fromdual.com/sites/default/files/gql_sudden_stop.png" alt="graph"&gt;&lt;/p&gt;
&lt;p&gt;The easiest thing to do in such a case would be to quickly look at the database with the &lt;code&gt;SHOW PROCESSLIST&lt;/code&gt; command and then it often becomes immediately clear where the problem lies. But customers often forget this or they are not fast enough. The General Query Log was already switched on for this customer, so this would be a great case for our General Query Log Data Warehouse!&lt;/p&gt;
&lt;h2 id="what-questions-should-my-data-warehouse-be-able-to-answer"&gt;What questions should my data warehouse be able to answer?&lt;/h2&gt;
&lt;p&gt;The generic question for this problem should be something like: &amp;ldquo;Who or what caused my system to behave abnormally?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;In technical terms, the question would be something like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Who: Which user or account was on the database with how many connections at the time in question? What was unusual about it?&lt;/li&gt;
&lt;li&gt;What: Which queries were running in which schema on the system at the time in question? Which of these queries were unusual?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-should-my-model-look-like"&gt;What should my model look like?&lt;/h2&gt;
&lt;p&gt;We can already derive some facts and dimensions from the question:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;User or account (user + host)&lt;/li&gt;
&lt;li&gt;Time&lt;/li&gt;
&lt;li&gt;Connections&lt;/li&gt;
&lt;li&gt;Schema&lt;/li&gt;
&lt;li&gt;Queries&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And this also results in 4 dimensions and the fact table:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.fromdual.com/sites/default/files/gql_model.png" alt="model"&gt;&lt;/p&gt;
&lt;h2 id="data-source"&gt;Data source&lt;/h2&gt;
&lt;p&gt;Where the data comes from is relatively easy to answer in this case: The customer provides his General Query Logs or you can also use the General Query Logs of our own systems for testing purposes.&lt;/p&gt;
&lt;h2 id="how-is-the-model-populated"&gt;How is the model populated?&lt;/h2&gt;
&lt;p&gt;Technically, this is known as an &lt;a href="https://en.wikipedia.org/wiki/Extract,_transform,_load" target="_blank" title="Extract, transform, load on Wikipedia"&gt;ETL process&lt;/a&gt; (Extract-Transform-Load). In our case, we have built a General Query Log parser that reads the General Query Log, prepares the data accordingly and saves it in the model.&lt;/p&gt;
&lt;h2 id="checking-the-model"&gt;Checking the model&lt;/h2&gt;
&lt;p&gt;And then we come to checking the model. We used test data from one of our systems for this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Which user was on the system at the time in question?&lt;/li&gt;
&lt;li&gt;Which user had how many connections open at the time in question?&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- --&gt;
&lt;pre&gt;&lt;code&gt;SELECT td.time, cd.user, COUNT(*) AS count
 FROM connection_dim cd
 JOIN query_fact AS qf ON qf.connection_id = cd.connection_id
 JOIN time_dim AS td ON td.time_id = qf.time_id
 JOIN date_dim AS dd ON dd.date_id = qf.date_id
 WHERE td.time BETWEEN '17:00' AND '18:30'
 AND dd.date = '2019-08-02'
 GROUP BY td.time, cd.user
 ORDER BY td.time ASC, cd.user
;
+----------+---------------+-------+
| time | user | count |
+----------+---------------+-------+
| 17:58:00 | UNKNOWN USER | 1 |
| 17:59:00 | brman | 58 |
| 17:59:00 | brman_catalog | 18 |
| 17:59:00 | root | 5 |
| 18:00:00 | brman | 296 |
| 18:00:00 | brman_catalog | 7 |
| 18:00:00 | root | 3 |
| 18:01:00 | brman_catalog | 18 |
| 18:01:00 | root | 3 |
| 18:06:00 | brman | 266 |
| 18:06:00 | brman_catalog | 6 |
| 18:07:00 | brman | 88 |
| 18:07:00 | brman_catalog | 7 |
| 18:10:00 | brman | 211 |
| 18:10:00 | brman_catalog | 18 |
| 18:10:00 | root | 4 |
| 18:11:00 | brman | 141 |
| 18:11:00 | root | 3 |
| 18:13:00 | brman | 4 |
| 18:14:00 | brman | 348 |
| 18:17:00 | brman | 354 |
| 18:17:00 | brman_catalog | 12 |
| 18:17:00 | root | 1 |
+----------+---------------+-------+
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Which account was on the system at the time in question?&lt;/li&gt;
&lt;li&gt;Which account had how many connections open at the time in question?&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- --&gt;
&lt;pre&gt;&lt;code&gt;SELECT td.time, cd.user, cd.hostname, COUNT(*) AS count
 FROM connection_dim cd
 JOIN query_fact AS qf ON qf.connection_id = cd.connection_id
 JOIN time_dim AS td ON td.time_id = qf.time_id
 JOIN date_dim AS dd ON dd.date_id = qf.date_id
 WHERE td.time BETWEEN '17:00' AND '18:30'
 AND dd.date = '2019-08-02'
 GROUP BY td.time, cd.user, cd.hostname
 ORDER BY td.time ASC, cd.user
;
+----------+---------------+--------------+-------+
| time | user | hostname | count |
+----------+---------------+--------------+-------+
| 17:58:00 | UNKNOWN USER | UNKNOWN HOST | 1 |
| 17:59:00 | brman | localhost | 58 |
| 17:59:00 | brman_catalog | localhost | 18 |
| 17:59:00 | root | localhost | 5 |
| 18:00:00 | brman | localhost | 296 |
| 18:00:00 | brman_catalog | localhost | 7 |
| 18:00:00 | root | localhost | 3 |
| 18:01:00 | brman_catalog | localhost | 18 |
| 18:01:00 | root | localhost | 3 |
| 18:06:00 | brman | localhost | 266 |
| 18:06:00 | brman_catalog | localhost | 6 |
| 18:07:00 | brman | localhost | 88 |
| 18:07:00 | brman_catalog | localhost | 7 |
| 18:10:00 | brman | localhost | 211 |
| 18:10:00 | brman_catalog | localhost | 18 |
| 18:10:00 | root | localhost | 4 |
| 18:11:00 | brman | localhost | 141 |
| 18:11:00 | root | localhost | 3 |
| 18:13:00 | brman | localhost | 4 |
| 18:14:00 | brman | localhost | 348 |
| 18:17:00 | brman | localhost | 354 |
| 18:17:00 | brman_catalog | localhost | 12 |
| 18:17:00 | root | localhost | 1 |
+----------+---------------+--------------+-------+
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;What was unusual about it?&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- --&gt;
&lt;pre&gt;&lt;code&gt;SELECT cd.user, td.time, COUNT(*) AS count
 FROM connection_dim cd
 JOIN query_fact AS qf ON qf.connection_id = cd.connection_id
 JOIN time_dim AS td ON td.time_id = qf.time_id
 JOIN date_dim AS dd ON dd.date_id = qf.date_id
 WHERE td.time BETWEEN '17:00' AND '18:30'
 AND dd.date = '2019-08-02'
 GROUP BY td.time, cd.user
 ORDER BY cd.user ASC, td.time ASC
;
+---------------+----------+-------+
| user | time | count |
+---------------+----------+-------+
| brman | 17:59:00 | 58 |
| brman | 18:00:00 | 296 |
| brman | 18:06:00 | 266 |
| brman | 18:07:00 | 88 |
| brman | 18:10:00 | 211 |
| brman | 18:11:00 | 141 |
| brman | 18:13:00 | 4 |
| brman | 18:14:00 | 348 |
| brman | 18:17:00 | 354 |
| brman_catalog | 17:59:00 | 18 |
| brman_catalog | 18:00:00 | 7 |
| brman_catalog | 18:01:00 | 18 |
| brman_catalog | 18:06:00 | 6 |
| brman_catalog | 18:07:00 | 7 |
| brman_catalog | 18:10:00 | 18 |
| brman_catalog | 18:17:00 | 12 |
| root | 17:59:00 | 5 |
| root | 18:00:00 | 3 |
| root | 18:01:00 | 3 |
| root | 18:10:00 | 4 |
| root | 18:11:00 | 3 |
| root | 18:17:00 | 1 |
| UNKNOWN USER | 17:58:00 | 1 |
+---------------+----------+-------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One could deduce here, for example, that the user brman had a relatively large number of open connections during the period in question. Whether this is unusual, we have too little data or the time period is too short.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Which queries were running on the system at the time in question and in which schema?&lt;/li&gt;
&lt;li&gt;Which of these queries were unusual?&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- --&gt;
&lt;pre&gt;&lt;code&gt;SELECT sd.schema_name, td.time, SUBSTR(std.statement_text, 1, 128) AS query
 FROM query_fact AS qf
 JOIN time_dim AS td ON td.time_id = qf.time_id
 JOIN schema_dim AS sd ON sd.schema_id = qf.schema_id
 JOIN statement_dim AS std ON std.statement_id = qf.statement_id
 WHERE td.time BETWEEN '17:00' AND '18:30'
 AND sd.schema_name = 'brman_catalog'
 AND std.command = 'Query'
 ORDER BY td.time, qf.statement_id
 LIMIT 10
;
+---------------+----------+----------------------------------------------------------------------------------------------------------------------------------+
| schema_name | time | query |
+---------------+----------+----------------------------------------------------------------------------------------------------------------------------------+
| brman_catalog | 17:59:00 | SET NAMES `utf8` |
| brman_catalog | 17:59:00 | SELECT COUNT ( * ) AS `cnt` FROM `information_schema` . `tables` WHERE `table_schema` = ? AND TABLE_NAME = ? |
| brman_catalog | 17:59:00 | SELECT COUNT ( * ) AS `cnt` FROM `information_schema` . `tables` WHERE `table_schema` = ? AND TABLE_NAME = ? |
| brman_catalog | 17:59:00 | CREATE TABLE `metadata` ( `id` TINYINT UNSIGNED NOT NULL AUTO_INCREMENT , `key` VARCHARACTER (?) NOT NULL , `value` VARCHARACTER |
| brman_catalog | 17:59:00 | INSERT INTO `metadata` ( `key` , `value` ) VALUES (...) |
| brman_catalog | 17:59:00 | INSERT INTO `metadata` ( `key` , `value` ) VALUES (...) |
| brman_catalog | 17:59:00 | CREATE TABLE `backups` ( `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT , `instance_name` VARCHARACTER (?) NOT NULL , `start_ts` |
| brman_catalog | 17:59:00 | CREATE TABLE `backup_details` ( `backup_id` INTEGER UNSIGNED NOT NULL , `hostname` VARCHARACTER (?) NULL , `binlog_file` VARCHAR |
| brman_catalog | 17:59:00 | CREATE TABLE `files` ( `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT , `schema_name` VARCHARACTER (?) NULL , `original_name` VAR |
| brman_catalog | 17:59:00 | CREATE TABLE `binary_logs` ( `id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT , `filename` VARCHARACTER (?) NOT NULL , `begin_ts` I |
+---------------+----------+----------------------------------------------------------------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="suggestions-for-improvement"&gt;Suggestions for improvement&lt;/h2&gt;
&lt;p&gt;Based on this first iteration of the model, you can already see which questions the model cannot yet answer or where the model is too imprecise. This can then be improved in a second round&amp;hellip;.&lt;/p&gt;
&lt;p&gt;Examples of this are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The granularity of the time dimension may be too coarse with an accuracy of minutes. Would it make more sense to use seconds?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The question of how long a connection was open is not so easy to answer. Perhaps a further fact table would be appropriate here?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; SELECT cd.connection_number, cd.user, cd.hostname, tdf.time AS time_from, tdt.time AS time_to, (UNIX_TIMESTAMP(tdt.time) - UNIX_TIMESTAMP(tdf.time)) AS duration
 FROM connection_dim AS cd
 JOIN query_fact AS qf1 ON cd.connection_id = qf1.connection_id
 JOIN time_dim AS tdf ON tdf.time_id = qf1.time_id
 JOIN statement_dim AS sdf ON sdf.statement_id = qf1.statement_id
 JOIN query_fact AS qf2 ON cd.connection_id = qf2.connection_id
 JOIN time_dim AS tdt ON tdt.time_id = qf2.time_id
 JOIN statement_dim AS sdt ON sdt.statement_id = qf2.statement_id
 WHERE tdf.time BETWEEN '17:00' AND '18:30'
 AND sdf.command = 'Connect'
 AND sdt.command = 'Quit'
 AND (UNIX_TIMESTAMP(tdt.time) - UNIX_TIMESTAMP(tdf.time)) &amp;gt; 0
 ORDER BY tdf.time
 ;
 +-------------------+-------+-----------+-----------+----------+----------+
 | connection_number | user | hostname | time_from | time_to | duration |
 +-------------------+-------+-----------+-----------+----------+----------+
 | 211 | brman | localhost | 17:59:00 | 18:00:00 | 60 |
 | 215 | root | localhost | 18:00:00 | 18:17:00 | 1020 |
 | 219 | brman | localhost | 18:06:00 | 18:07:00 | 60 |
 | 225 | brman | localhost | 18:10:00 | 18:11:00 | 60 |
 | 226 | brman | localhost | 18:13:00 | 18:14:00 | 60 |
 +-------------------+-------+-----------+-----------+----------+----------+
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Of course, it would be exciting if an AI were used to solve the problem. How do you train it correctly and does it find the problem once it has been trained?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So much for the little gimmick of building a data warehouse&amp;hellip;&lt;/p&gt;</description></item><item><title>FromDual Performance Monitor for MariaDB 2.1.0 has been released</title><link>https://www.fromdual.com/blog/fpmmm-release-notes/fromdual-performance-monitor-for-mariadb-2.1.0-has-been-released/</link><pubDate>Sat, 09 Dec 2023 18:27:02 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/fpmmm-release-notes/fromdual-performance-monitor-for-mariadb-2.1.0-has-been-released/</guid><description>&lt;p&gt;FromDual has the pleasure to announce the release of the new version 2.1.0 of its popular Database Performance Monitor for MariaDB and Galera Cluster &lt;a href="https://www.fromdual.com/fpmmm-installation-guide"&gt;&lt;code&gt;fpmmm&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The FromDual Performance Monitor for MariaDB (&lt;code&gt;fpmmm&lt;/code&gt;) enables DBAs and System Administrators to monitor and understand what is going on inside their MariaDB database instances and on the machines where the databases reside.&lt;/p&gt;
&lt;p&gt;More detailed information you can find in the &lt;a href="https://www.fromdual.com/fpmmm-installation-guide" title="fpmmm Installation Guide"&gt;fpmmm Installation Guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="download"&gt;Download&lt;/h2&gt;
&lt;p&gt;The new FromDual Performance Monitor for MariaDB (&lt;code&gt;fpmmm&lt;/code&gt;) can be downloaded from &lt;a href="https://www.fromdual.com/download" title="FromDual download"&gt;here&lt;/a&gt; or you can use our &lt;a href="https://www.fromdual.com/repositories/" title="FromDual repositories"&gt;FromDual repositories&lt;/a&gt;. How to install and use &lt;code&gt;fpmmm&lt;/code&gt; is documented in the &lt;a href="https://www.fromdual.com/fpmmm-installation-guide" title="fpmmm installation guide"&gt;fpmmm Installation Guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the inconceivable case that you find a bug in the FromDual Performance Monitor for MariaDB please report it to the FromDual &lt;a href="https://support.fromdual.com/bugs/login_page.php" target="_blank" title="FromDual Bug-tracker"&gt;Bug-tracker&lt;/a&gt; or just send us an [email](mailto:contact@fromdual.com?Subject=Bug report for fpmmm).&lt;/p&gt;
&lt;p&gt;Any feedback, statements and testimonials are welcome as well! Please send them [to us](mailto:feedback@fromdual.com?Subject=Feedback for fpmmm &amp;ldquo;Feedback for fpmmm&amp;rdquo;).&lt;/p&gt;
&lt;h2 id="monitoring-as-a-service-maas"&gt;Monitoring as a Service (MaaS)&lt;/h2&gt;
&lt;p&gt;You do not want to set-up your Database monitoring yourself? No problem: Choose our MariaDB &lt;a href="https://www.fromdual.com/monitoring-as-a-service-maas" title="Monitoring as a Service (MaaS) for MariaDB"&gt;Monitoring as a Service&lt;/a&gt; (Maas) program to safe time and costs!&lt;/p&gt;
&lt;h2 id="installation-of-performance-monitor-210"&gt;Installation of Performance Monitor 2.1.0&lt;/h2&gt;
&lt;p&gt;A complete guide on how to install FromDual Performance Monitor you can find in the &lt;a href="https://www.fromdual.com/fpmmm-installation-guide" title="fpmmm Installation Guide"&gt;fpmmm Installation Guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="upgrade-of-fpmmm-tarball-from-1x-to-210"&gt;Upgrade of fpmmm tarball from 1.x to 2.1.0&lt;/h2&gt;
&lt;p&gt;There are some changes in the configuration file (&lt;code&gt;fpmmm.conf&lt;/code&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The access rights should be change as follows: &lt;code&gt;chmod 600 /etc/fpmmm.conf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The key &lt;code&gt;Methode&lt;/code&gt; was spelled wrong in the configuration file. It was renamed to &lt;code&gt;Method&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The key &lt;code&gt;PidFile&lt;/code&gt; is ambiguous which could lead to problems and bugs. Thus it was changed to either &lt;code&gt;MyPidFile&lt;/code&gt; for fpmmm and &lt;code&gt;DbPidFile&lt;/code&gt; for the database.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Upgrade with DEB/RPM packages should happen automatically. For tarballs follow this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; cd /opt
shell&amp;gt; tar xf /download/fpmmm-2.1.0.tar.gz
shell&amp;gt; rm -f fpmmm
shell&amp;gt; ln -s fpmmm-2.1.0 fpmmm
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="changes-in-fromdual-performance-monitor-for-mariadb-210"&gt;Changes in FromDual Performance Monitor for MariaDB 2.1.0&lt;/h2&gt;
&lt;p&gt;This release contains new features and various bug fixes.&lt;/p&gt;
&lt;p&gt;You can verify your current FromDual Performance Monitor for MariaDB version with the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell&amp;gt; /opt/fpmmm/bin/fpmmm --version
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="general"&gt;General&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Comments and some more debugging information added.&lt;/li&gt;
&lt;li&gt;All needed logging added for tracking down the problem of bad stat output.&lt;/li&gt;
&lt;li&gt;New variables fixed.&lt;/li&gt;
&lt;li&gt;Error messages improved.&lt;/li&gt;
&lt;li&gt;Fix error output.&lt;/li&gt;
&lt;li&gt;Version 10.11.1 was not split up correctly, fixed.&lt;/li&gt;
&lt;li&gt;myEnv updated to fix bad MySQL detection on Ubuntu from repository.&lt;/li&gt;
&lt;li&gt;Old database version error fixed if connection to API does not work.&lt;/li&gt;
&lt;li&gt;Disable smart module by default to avoid error messages.&lt;/li&gt;
&lt;li&gt;Removed /etc/fpmmm folder everywhere.&lt;/li&gt;
&lt;li&gt;rc made unique, tests fixed.&lt;/li&gt;
&lt;li&gt;Default path locations brought up to date.&lt;/li&gt;
&lt;li&gt;DbPidFile location is new under /run.&lt;/li&gt;
&lt;li&gt;All tests for MariaDB 10.11 passed.&lt;/li&gt;
&lt;li&gt;CacheFileBase bug fixed.&lt;/li&gt;
&lt;li&gt;FreeDSx/SNMP upgraded from 0.4 to 0.5.&lt;/li&gt;
&lt;li&gt;DB connection handling improved and made more OO style.&lt;/li&gt;
&lt;li&gt;Configuration file parser made more stable for syntax errors.&lt;/li&gt;
&lt;li&gt;Error log logged to systemd message improved.&lt;/li&gt;
&lt;li&gt;Option &amp;ndash;version is now done before check options.&lt;/li&gt;
&lt;li&gt;PHP requirement version specified.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="templates"&gt;Templates&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Templates improved.&lt;/li&gt;
&lt;li&gt;Link for triggers fixed.&lt;/li&gt;
&lt;li&gt;Working period added to all graphs.&lt;/li&gt;
&lt;li&gt;Zabbix 6 templates added to Makefile.&lt;/li&gt;
&lt;li&gt;Zabbix 6.0 templates added (6.0.21) and renamed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="agent"&gt;Agent&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;All variables from templates removed, test added for fpmmm MRRELEASE.&lt;/li&gt;
&lt;li&gt;Fix MRRLEASE tag in fpmmm template fixed again.&lt;/li&gt;
&lt;li&gt;Function writeDataToCache improved for tracking customer problems.&lt;/li&gt;
&lt;li&gt;CacheFile is now protected with flock, this should resolve issues with lost brman items.&lt;/li&gt;
&lt;li&gt;fpmmm version problem error message improved.&lt;/li&gt;
&lt;li&gt;Disabled = True is not recognized correctly and no error was thrown. This is fixed now.&lt;/li&gt;
&lt;li&gt;Messages were not handled correctly with SNMP output. This is fixed now.&lt;/li&gt;
&lt;li&gt;mdstat message removed from error log.&lt;/li&gt;
&lt;li&gt;Make error messages around sending data nicer.&lt;/li&gt;
&lt;li&gt;apt-get/yum messages replaced by dnf/apt.&lt;/li&gt;
&lt;li&gt;Error message made more clear if php-cli package is missing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="server"&gt;Server&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Trigger too many filesystem locks set from MULTIPLE to SINGLE, threshold increased from 10000 to 16384 (mariadb MaxNOFiles) and message improved.&lt;/li&gt;
&lt;li&gt;Working time added to server graphs.&lt;/li&gt;
&lt;li&gt;iostat items remove from server template.&lt;/li&gt;
&lt;li&gt;Available disks are now reported with space in between.&lt;/li&gt;
&lt;li&gt;Disk sda5 removed from template, network interfaces enp4s0f1 and bond0 added to template, disks vdb1 and md1 added to template.&lt;/li&gt;
&lt;li&gt;CPU usage details removed, guest_nice item added.&lt;/li&gt;
&lt;li&gt;Swapping items added.&lt;/li&gt;
&lt;li&gt;Typo in host screen fixed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="galera"&gt;Galera&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Galera group replication latency added.&lt;/li&gt;
&lt;li&gt;In addition to old wsrep_causal_reads the new wsrep_sync_wait variable was added including the trigger.&lt;/li&gt;
&lt;li&gt;Non Galera node is not detected as such and gives ugly error message, fixed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="innodb"&gt;InnoDB&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Item innodb log write requests and innodb log writes fixed in innodb template.&lt;/li&gt;
&lt;li&gt;Item InnoDB Trx Log bytes written renamed to InnoDB Log bytes written, graph InnoDB Log Activity removed because it is redundant now.&lt;/li&gt;
&lt;li&gt;Item innodb_redo_log_capacity added for MySQL 8.0.&lt;/li&gt;
&lt;li&gt;InnoDB buffer pool wait free trigger has wrong filter for item. fixed.&lt;/li&gt;
&lt;li&gt;InnoDB Buffer Pool wait for free pages trigger added link to item value.&lt;/li&gt;
&lt;li&gt;innodb_file_format also removed from template.&lt;/li&gt;
&lt;li&gt;InnoDB buffer pool wait free trigger added.&lt;/li&gt;
&lt;li&gt;FromDual.MySQL.innodb.Innodb_data_pending_fsyncs changed from absolute values to change_per_second to make graph useful.&lt;/li&gt;
&lt;li&gt;Links fixed in triggers for innodb module.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="mysql"&gt;MySQL&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;DB is soon out of support message downgraded from average to warning.&lt;/li&gt;
&lt;li&gt;Item name fixed.&lt;/li&gt;
&lt;li&gt;Link for table open cache trigger adjusted.&lt;/li&gt;
&lt;li&gt;Trigger for mysql/mariadb support ends was changed from multiple to single to reduce noise.&lt;/li&gt;
&lt;li&gt;com_call_procedure status counter fixed in module and template.&lt;/li&gt;
&lt;li&gt;storage_engine item remove from template, processlist item waiting for table level lock fixed.&lt;/li&gt;
&lt;li&gt;TOC was updated in template and improved and cleaned-up.&lt;/li&gt;
&lt;li&gt;Unlock table item is not collected any more and trigger was removed, caused useless alerts.&lt;/li&gt;
&lt;li&gt;Modern TOC handling implemented.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="process"&gt;Process&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Process module refactored, more logging and tests added.&lt;/li&gt;
&lt;li&gt;Bug in process module fixed: /proc/PID/stat was not parsed correctly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="security"&gt;Security&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Links fixed in triggers for security module.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="master"&gt;Master&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Binlog event count and binlog avg event size removed from master template because we cannot calculate those values.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="backup"&gt;Backup&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Backup template duration URL fixed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="packaging"&gt;Packaging&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Packages added for Debian 10, Debian 11, Debian 12, Ubuntu 20.04, Ubuntu 22.04, Redhat 8 and Redhat 9.&lt;/li&gt;
&lt;li&gt;Package bug with fpmmm.ini fixed.&lt;/li&gt;
&lt;li&gt;Debian build version increased and package build config error fixed again.&lt;/li&gt;
&lt;li&gt;Debian package revision introduced.&lt;/li&gt;
&lt;li&gt;Bug in config copy during postinst fixed.&lt;/li&gt;
&lt;li&gt;Package installation error overwriting &lt;code&gt;fpmmm.conf&lt;/code&gt; fixed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For subscriptions of commercial use of &lt;code&gt;fpmmm&lt;/code&gt; please [get in contact](mailto:contact@fromdual.com?Subject=Commercial use of fpmmm &amp;ldquo;Contact FromDual&amp;rdquo;) with us.&lt;/p&gt;</description></item><item><title>InnoDB Deadlock on SELECT? Not possible! Or Is It?</title><link>https://www.fromdual.com/blog/innodb-deadlock-on-select-not-possible-or-is-it/</link><pubDate>Sat, 25 Nov 2023 16:58:41 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/innodb-deadlock-on-select-not-possible-or-is-it/</guid><description>&lt;p&gt;Translated by &lt;a href="https://www.deepl.com/en/translator" target="_blank"&gt;deepl.com&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Two points in advance:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;A deadlock is a state in which two different transactions are no longer able to continue working because each transaction holds a lock that the other transaction would need. Because both transactions are now waiting for the other transaction to release their locks, neither transaction will release their respective locks. And that would last forever. To avoid this, the MariaDB instance intervenes and kills the transaction that has done less work. The application then receives a deadlock error message of this type:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A general mantra in the MariaDB ecosystem is that a &lt;code&gt;SELECT&lt;/code&gt; does not cause locks (exception: &lt;code&gt;FOR UPDATE&lt;/code&gt; or &lt;code&gt;LOCK IN SHARE MODE&lt;/code&gt;) and therefore cannot be part of a deadlock.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="the-problem"&gt;The problem&lt;/h2&gt;
&lt;p&gt;A long-standing customer comes to the FromDual remote DBA team with a request to explain a deadlock situation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hello FromDual Team,
I need your expertise on the subject of deadlocks.
When would it suit you?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The situation is as follows: Transaction 1 consists of a simple &lt;code&gt;INSERT&lt;/code&gt;. Transaction 2 consists of a &lt;code&gt;SELECT&lt;/code&gt;. This should NOT actually cause a deadlock!&lt;/p&gt;
&lt;p&gt;We first check the following points&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Are all tables affected by these queries properly indexed? Yes, they are. The queries are all running perfectly!&lt;/li&gt;
&lt;li&gt;Is the &lt;code&gt;SELECT&lt;/code&gt; query possibly part of a larger transaction (NOT an auto-commit transaction) and therefore not the actual cause of the deadlock? No, it is not. They are auto-commit transactions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What now? What else needs to be said for clarification: The &lt;code&gt;SELECT&lt;/code&gt; is sent with a very high cadence, i.e. approx. every 5 ms!&lt;/p&gt;
&lt;p&gt;It is clear that the &lt;code&gt;INSERT&lt;/code&gt; generates locks. It is also displayed. But why does the &lt;code&gt;SELECT&lt;/code&gt; command generate locks? These are also displayed!&lt;/p&gt;
&lt;p&gt;So we try to break the problem down into individual steps.&lt;/p&gt;
&lt;h2 id="the-approach"&gt;The approach&lt;/h2&gt;
&lt;p&gt;The query looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SET @id = (SELECT id FROM test WHERE id = 3);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we pack this query into an explicit transaction, we can even see the locks:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; START TRANSACTION;
SQL&amp;gt; SET @id = (SELECT id FROM test WHERE id = 3);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and in a second session:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SELECT * FROM information_schema.INNODB_TRX&amp;lt;br&amp;gt;G
*************************** 1. row ***************************
 trx_id: 0
 trx_state: RUNNING
 trx_started: 2023-11-19 15:27:09
 trx_requested_lock_id: NULL
 trx_wait_started: NULL
 trx_weight: 2
 trx_mysql_thread_id: 3765
 trx_query: NULL
 trx_operation_state:
 trx_tables_in_use: 0
 trx_tables_locked: 1
 trx_lock_structs: 2
 trx_lock_memory_bytes: 1128
 trx_rows_locked: 1
 trx_rows_modified: 0
 trx_concurrency_tickets: 0
 trx_isolation_level: REPEATABLE READ
 trx_unique_checks: 1
 trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_is_read_only: 0
trx_autocommit_non_locking: 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately, we cannot see what kind of lock (IS) it is, because the view &lt;code&gt;INNODB_LOCKS&lt;/code&gt; is empty.&lt;/p&gt;
&lt;h2 id="the-solution"&gt;The solution&lt;/h2&gt;
&lt;p&gt;If we do the same experiment with &amp;ldquo;normal&amp;rdquo; &lt;code&gt;SELECT&lt;/code&gt;s:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; START TRANSACTION; SELECT id FROM test WHERE id = 3;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; START TRANSACTION; SELECT id INTO @id FROM test WHERE id = 3;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;we do NOT see any locks:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL&amp;gt; SELECT * FROM information_schema.INNODB_TRX&amp;lt;br&amp;gt;G
*************************** 1. row ***************************
 trx_id: 0
 trx_state: RUNNING
 trx_started: 2023-11-19 15:31:35
 trx_requested_lock_id: NULL
 trx_wait_started: NULL
 trx_weight: 0
 trx_mysql_thread_id: 3765
 trx_query: NULL
 trx_operation_state:
 trx_tables_in_use: 0
 trx_tables_locked: 0
 trx_lock_structs: 0
 trx_lock_memory_bytes: 1128
 trx_rows_locked: 0
 trx_rows_modified: 0
 trx_concurrency_tickets: 0
 trx_isolation_level: REPEATABLE READ
 trx_unique_checks: 1
 trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_is_read_only: 0
trx_autocommit_non_locking: 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So it seems that the construct &lt;code&gt;SET @id = (...)&lt;/code&gt; causes this IS lock. The customer rewrites his application and shortly afterwards we receive the following message:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hello FromDual team,
Your tip was spot on.
No more deadlocks since Friday lunchtime.
Thank you and have a nice weekend.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;img src="https://www.fromdual.com/sites/default/files/innodb_deadlocks.png" title="InnoDB Deadlocks" width="640" /&gt;
&lt;h2 id="further-clarified-questions"&gt;Further clarified questions&lt;/h2&gt;
&lt;p&gt;MySQL 8.0 behaves the same? Yes, exactly the same.&lt;/p&gt;
&lt;h2 id="addendum"&gt;Addendum&lt;/h2&gt;
&lt;p&gt;My dear colleague Matthias gave me a follow-up idea: What about MariaDB Stored Procedures and Stored Functions?&lt;/p&gt;
&lt;p&gt;The two tests here:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DELIMITER //

CREATE OR REPLACE PROCEDURE locktestsp (INOUT id INT)
BEGIN
 SELECT id INTO id FROM test WHERE id = id LIMIT 1;
END;
//

DELIMITER ;

SET @id = 3;
START TRANSACTION;
CALL locktestsp(@id);
SELECT @id;

SELECT trx_tables_locked, trx_lock_structs, trx_rows_locked FROM information_schema.INNODB_TRX;
+-------------------+------------------+-----------------+
| trx_tables_locked | trx_lock_structs | trx_rows_locked |
+-------------------+------------------+-----------------+
| 0 | 0 | 0 |
+-------------------+------------------+-----------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and here:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DELIMITER //

CREATE OR REPLACE FUNCTION locktestsf (IN id INT)
RETURNS CHAR(50) DETERMINISTIC
BEGIN
 SELECT id INTO id FROM test WHERE id = id LIMIT 1;
 RETURN id;
END;
//

DELIMITER ;

START TRANSACTION;
SELECT locktestsf(3);

SELECT trx_tables_locked, trx_lock_structs, trx_rows_locked FROM information_schema.INNODB_TRX;
+-------------------+------------------+-----------------+
| trx_tables_locked | trx_lock_structs | trx_rows_locked |
+-------------------+------------------+-----------------+
| 0 | 0 | 0 |
+-------------------+------------------+-----------------+
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Ops Center File Transfer Tool</title><link>https://www.fromdual.com/blog/ops-center-tools-file-transfer/</link><pubDate>Thu, 16 Mar 2023 15:47:34 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/ops-center-tools-file-transfer/</guid><description/></item><item><title>Upgrading MariaDB to the pre-latest minor release</title><link>https://www.fromdual.com/blog/upgrading-mariadb-to-the-pre-latest-minor-release/</link><pubDate>Wed, 08 Feb 2023 13:45:30 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/blog/upgrading-mariadb-to-the-pre-latest-minor-release/</guid><description>&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; MariaDB Community Server is release every 3 months. The exact date is not known but it is typically about 2 to 3 weeks after the &lt;a href="https://www.fromdual.com/security#oracle-critical-patch-update-advisory-for-mysql" target="_blank"&gt;MySQL/Oracle CPU&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We upgrade regularly customer systems, also their MariaDB Galera Cluster systems. Because we made in the past some very bad experience upgrading production MariaDB Galera Clusters short after release date we became a bit more careful. Our new policy is: We wait a few weeks before installing a new release.&lt;/p&gt;
&lt;p&gt;This week we had the situation that on Monday a new MariaDB release came out and on Wednesday we had to do the Cluster upgrade. So only 2 days in between. Too short time for my taste. But we did not want to omit the upgrade because it was already more than 6 months since the last upgrade&amp;hellip;&lt;/p&gt;
&lt;p&gt;So we decided to install the pre-latest MariaDB release. Technically it means: Customer was on 10.6.9, 10.6.12 is out (and already available in the repositories) but we want to upgrade to 10.6.11. Additionally we also wanted to upgrade the O/S (Debian 11). So how to do this quite complex task? In short:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set all MariaDB related packages to hold.&lt;/li&gt;
&lt;li&gt;Upgrade all other packages including a reboot of the machine.&lt;/li&gt;
&lt;li&gt;Unhold all MariaDB related packages.&lt;/li&gt;
&lt;li&gt;Install specific MariaDB packages which are not the newest one.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="set-mariadb-related-packages-to-hold"&gt;Set MariaDB related packages to hold&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;dpkg -l | grep mariadb
ii libdbd-mariadb-perl 1.21-3 amd64 Perl5 database interface to the MariaDB/MySQL databases
ii libmariadb3:amd64 1:10.6.9+maria~deb11 amd64 MariaDB database client library
ii libmariadb3-compat 1:10.6.9+maria~deb11 amd64 MariaDB database client library MySQL compat package
ii libmariadbclient18 1:10.6.9+maria~deb11 amd64 Virtual package to satisfy external libmariadbclient18 depends
ii mariadb-client-10.6 1:10.6.9+maria~deb11 amd64 MariaDB database client binaries
ii mariadb-client-core-10.6 1:10.6.9+maria~deb11 amd64 MariaDB database core client binaries
ii mariadb-common 1:10.6.9+maria~deb11 all MariaDB common configuration files
ii mariadb-server-10.6 1:10.6.9+maria~deb11 amd64 MariaDB database server binaries
ii mariadb-server-core-10.6 1:10.6.9+maria~deb11 amd64 MariaDB database core server files

apt-mark hold galera-4 libmariadb3-compat libmariadb3 libmariadbclient18 mariadb-client-10.6 mariadb-client-core-10.6 mariadb-common mariadb-server-10.6 mariadb-server-core-10.6 mysql-common

apt-mark showhold
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="upgrade-al-other-os-dependent-packages"&gt;Upgrade al other O/S dependent packages&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;apt update

apt list --upgradable
Listing... Done
galera-4/unknown 26.4.14-deb11 amd64 [upgradable from: 26.4.11-0+deb11u1]
libmariadb3-compat/unknown 1:10.6.12+maria~deb11 amd64 [upgradable from: 1:10.6.9+maria~deb11]
libmariadb3/unknown 1:10.6.12+maria~deb11 amd64 [upgradable from: 1:10.6.9+maria~deb11]
libmariadbclient18/unknown 1:10.6.12+maria~deb11 amd64 [upgradable from: 1:10.6.9+maria~deb11]
libssl1.1/stable-security 1.1.1n-0+deb11u4 amd64 [upgradable from: 1.1.1n-0+deb11u3]
mariadb-client-10.6/unknown 1:10.6.12+maria~deb11 amd64 [upgradable from: 1:10.6.9+maria~deb11]
mariadb-client-core-10.6/unknown 1:10.6.12+maria~deb11 amd64 [upgradable from: 1:10.6.9+maria~deb11]
mariadb-common/unknown 1:10.6.12+maria~deb11 all [upgradable from: 1:10.6.9+maria~deb11]
mariadb-server-10.6/unknown 1:10.6.12+maria~deb11 amd64 [upgradable from: 1:10.6.9+maria~deb11]
mariadb-server-core-10.6/unknown 1:10.6.12+maria~deb11 amd64 [upgradable from: 1:10.6.9+maria~deb11]
mysql-common/unknown 1:10.6.12+maria~deb11 all [upgradable from: 5.8+1.0.7]
openssl/stable-security 1.1.1n-0+deb11u4 amd64 [upgradable from: 1.1.1n-0+deb11u3]

apt upgrade
The following packages have been kept back:
 galera-4 libmariadb3 libmariadb3-compat libmariadbclient18 mariadb-client-10.6 mariadb-client-core-10.6 mariadb-common mariadb-server-10.6 mariadb-server-core-10.6 mysql-common
The following packages will be upgraded:
 libssl1.1 openssl
2 upgraded, 0 newly installed, 0 to remove and 10 not upgraded.

cat /var/run/reboot-required
# reboot [-f]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="unhold-mariadb-related-packages"&gt;Unhold MariaDB related packages&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;apt-mark unhold galera-4 libmariadb3-compat libmariadb3 libmariadbclient18 mariadb-client-10.6 mariadb-client-core-10.6 mariadb-common mariadb-server-10.6 mariadb-server-core-10.6 mysql-common

apt-mark showhold
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="install-specific-mariadb-version-packages"&gt;Install specific MariaDB version packages&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;apt list -a galera-4

apt install galera-4=26.4.13-bullseye libmariadb3-compat=1:10.6.11+maria~deb11 libmariadb3=1:10.6.11+maria~deb11 libmariadbclient18=1:10.6.11+maria~deb11 mariadb-client-10.6=1:10.6.11+maria~deb11 mariadb-client-core-10.6=1:10.6.11+maria~deb11 mariadb-common=1:10.6.11+maria~deb11 mariadb-server-10.6=1:10.6.11+maria~deb11 mariadb-server-core-10.6=1:10.6.11+maria~deb11 mysql-common=1:10.6.11+maria~deb11

# To avoid 2 database restarts we can also do the reboot here
systemctl restart mariadb

mariadb-upgrade --user=root

apt list --upgradable
Listing... Done
galera-4/unknown 26.4.14-deb11 amd64 [upgradable from: 26.4.13-bullseye]
libmariadb3-compat/unknown 1:10.6.12+maria~deb11 amd64 [upgradable from: 1:10.6.11+maria~deb11]
libmariadb3/unknown 1:10.6.12+maria~deb11 amd64 [upgradable from: 1:10.6.11+maria~deb11]
libmariadbclient18/unknown 1:10.6.12+maria~deb11 amd64 [upgradable from: 1:10.6.11+maria~deb11]
mariadb-client-10.6/unknown 1:10.6.12+maria~deb11 amd64 [upgradable from: 1:10.6.11+maria~deb11]
mariadb-client-core-10.6/unknown 1:10.6.12+maria~deb11 amd64 [upgradable from: 1:10.6.11+maria~deb11]
mariadb-common/unknown 1:10.6.12+maria~deb11 all [upgradable from: 1:10.6.11+maria~deb11]
mariadb-server-10.6/unknown 1:10.6.12+maria~deb11 amd64 [upgradable from: 1:10.6.11+maria~deb11]
mariadb-server-core-10.6/unknown 1:10.6.12+maria~deb11 amd64 [upgradable from: 1:10.6.11+maria~deb11]
mysql-common/unknown 1:10.6.12+maria~deb11 all [upgradable from: 1:10.6.11+maria~deb11]
&lt;/code&gt;&lt;/pre&gt;</description></item></channel></rss>