<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>FromDual GmbH</title><link>https://www.fromdual.com/fr/aggregator/categories/3/</link><description>Recent content on FromDual GmbH</description><generator>Hugo</generator><language>fr-FR</language><managingEditor>oli.sennhauser@fromdual.com (Oli Sennhauser)</managingEditor><webMaster>oli.sennhauser@fromdual.com (Oli Sennhauser)</webMaster><copyright>© FromDual GmbH</copyright><atom:link href="https://www.fromdual.com/fr/aggregator/categories/3/index.xml" rel="self" type="application/rss+xml"/><item><title>Comment charger rapidement des données dans la base de données ?</title><link>https://www.fromdual.com/fr/blog/charger-rapidement-les-donnees-dans-la-base-de-donnees/</link><pubDate>Wed, 11 Feb 2026 10:04:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/blog/charger-rapidement-les-donnees-dans-la-base-de-donnees/</guid><description>&lt;p&gt;Chez notre dernier client, nous avons vraiment dû résoudre quelques questions passionnantes ! Notamment parce que la base de données n&amp;rsquo;était pas vraiment petite.&lt;/p&gt;
&lt;p&gt;Voici quelques données clés : CPU : 2 sockets x 24 cœurs x 2 threads = 96 vCores, 756 G RAM, 2 x 10 To SSD PCIe en RAID-10 et 7 To de données, plusieurs milliers de clients, en forte croissance.&lt;/p&gt;
&lt;p&gt;Débit actuel : 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 en moyenne sur 30 jours. Tendance en forte hausse. Application et requêtes non optimisées de manière cohérente. Configuration de la base de données : « à la pointe de la technologie », non vérifiée par des benchmarks. Utilisation du CPU d&amp;rsquo;environ 50 % en moyenne, avec des pics supérieurs. Le système d&amp;rsquo;E/S dispose encore de capacités libres.&lt;/p&gt;
&lt;p&gt;Le client collecte des données de position et d&amp;rsquo;autres données relatives aux appareils et les stocke dans la base de données. Il s&amp;rsquo;agit donc d&amp;rsquo;un problème IoT classique (avec séries chronologiques, table indexée en grappes, etc.).&lt;/p&gt;
&lt;p&gt;La question qu&amp;rsquo;il a posée est la suivante : comment copier le plus rapidement possible des données d&amp;rsquo;une table (données en attente, une sorte de file d&amp;rsquo;attente) vers une autre table (données finales, par client) ?&lt;/p&gt;
&lt;p&gt;Le flux de données se présente comme suit :&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;Trois variantes différentes pour copier les données étaient disponibles.&lt;/p&gt;
&lt;h2 id="variante-1-insert-et-delete-forme-la-plus-simple"&gt;Variante 1: &lt;code&gt;INSERT&lt;/code&gt; et &lt;code&gt;DELETE&lt;/code&gt; (forme la plus simple)&lt;/h2&gt;
&lt;p&gt;La variante la plus simple est &lt;code&gt;INSERT&lt;/code&gt; et &lt;code&gt;DELETE&lt;/code&gt;. Cette variante est particulièrement problématique car MariaDB/MySQL et PostgreSQL ont activé &lt;code&gt;AUTOCOMMIT&lt;/code&gt; par défaut (&lt;a href="https://dev.mysql.com/doc/refman/8.4/en/innodb-autocommit-commit-rollback.html" target="_blank"&gt;ici&lt;/a&gt;, &lt;a href="https://mariadb.com/docs/server/reference/sql-statements/transactions/start-transaction" target="_blank"&gt;ici&lt;/a&gt;, &lt;a href="https://www.postgresql.org/docs/current/ecpg-sql-set-autocommit.html" target="_blank"&gt;ici&lt;/a&gt; et &lt;a href="https://www.cybertec-postgresql.com/en/disabling-autocommit-in-postgresql-can-damage-your-health/" target="_blank"&gt;ici&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Pour mieux comprendre, voici un exemple de 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;Si nous voulons copier 20 000 lignes, cette variante génère 40 000 &lt;code&gt;COMMIT&lt;/code&gt; (&lt;code&gt;fsync&lt;/code&gt;) et 42 000 allers-retours réseau !&lt;/p&gt;
&lt;h2 id="variante-2-start-transaction-et-insert-et-delete"&gt;Variante 2: &lt;code&gt;START TRANSACTION&lt;/code&gt; et &lt;code&gt;INSERT&lt;/code&gt; et &lt;code&gt;DELETE&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Cette variante est utilisée par les développeurs de bases de données plus expérimentés. Voici le pseudocode correspondant :&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;Si nous voulons copier 20 000 lignes dans cet exemple, cette variante ne génère plus que 2 000 &lt;code&gt;COMMIT&lt;/code&gt; (&lt;code&gt;fsync&lt;/code&gt;) ! Soit 20 fois moins ! Mais en contrepartie, 46 000 allers-retours réseau (10 % de plus).&lt;/p&gt;
&lt;h2 id="variante-3-start-transaction-et-insert-et-delete-optimisés"&gt;Variante 3: &lt;code&gt;START TRANSACTION&lt;/code&gt; et &lt;code&gt;INSERT&lt;/code&gt; et &lt;code&gt;DELETE&lt;/code&gt; optimisés&lt;/h2&gt;
&lt;p&gt;Cette variante est un peu plus exigeante sur le plan technique. Elle est utilisée lorsque l&amp;rsquo;on souhaite se rapprocher un peu plus des limites du possible. Voici le pseudocode correspondant :&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;Cette troisième variante ne génère également que 2 k &lt;code&gt;COMMIT&lt;/code&gt; (&lt;code&gt;fsync&lt;/code&gt;) pour 20 k lignes, mais évite la boucle via les instructions &lt;code&gt;INSERT&lt;/code&gt; et &lt;code&gt;DELETE&lt;/code&gt; dans la base de données. Nous économisons ainsi d&amp;rsquo;une part les allers-retours réseau (plus que 10 k) et les cycles CPU sur la base de données (qui sont difficilement évolutifs) pour analyser les requêtes.&lt;/p&gt;
&lt;h2 id="configuration-du-test"&gt;Configuration du test&lt;/h2&gt;
&lt;p&gt;Pour tester le tout, nous avons préparé un petit 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="préparation-et-exécution-avec-mariadbmysql"&gt;Préparation et exécution avec MariaDB/MySQL&lt;/h3&gt;
&lt;p&gt;Vous pouvez effectuer vous-même ces tests à l&amp;rsquo;aide des commandes suivantes :&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;Chacun peut obtenir les valeurs mesurées à l&amp;rsquo;aide du script de test correspondant.&lt;/p&gt;
&lt;h3 id="préparation-et-exécution-avec-postgresql"&gt;Préparation et exécution avec PostgreSQL&lt;/h3&gt;
&lt;p&gt;Vous pouvez effectuer ces tests vous-même à l&amp;rsquo;aide des commandes suivantes :&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;Chacun peut obtenir les valeurs mesurées à l&amp;rsquo;aide du script de test correspondant.&lt;/p&gt;
&lt;h2 id="résultats"&gt;Résultats&lt;/h2&gt;
&lt;p&gt;Afin d&amp;rsquo;éviter toute discussion inutile, nous n&amp;rsquo;avons indiqué ici « que » les performances relatives (durée d&amp;rsquo;exécution), comme le fait MarkC ces derniers temps. Nos valeurs mesurées peuvent être mises à disposition de manière bilatérale. Elles peuvent toutefois être facilement reproduites à l&amp;rsquo;aide du script de test.&lt;/p&gt;
&lt;p&gt;Moins, c&amp;rsquo;est mieux :&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;/th&gt;
 &lt;th&gt;Variante 1&lt;/th&gt;
 &lt;th&gt;Variante 2&lt;/th&gt;
 &lt;th&gt;Variante 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;**Attention ** : les valeurs de MariaDB/MySQL et PostgreSQL ne peuvent PAS être comparées directement !&lt;/p&gt;
&lt;br&gt;
&lt;p&gt;Et voici l&amp;rsquo;évaluation graphique :&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="remarques"&gt;Remarques&lt;/h2&gt;
&lt;p&gt;Avec des disques plus rapides, la différence entre 1 et 2/3 n&amp;rsquo;aurait probablement pas été aussi importante. Les tests effectués chez le client n&amp;rsquo;ont montré « qu&amp;rsquo;un » facteur 5 (au lieu d&amp;rsquo;un facteur 9 à 16) de différence.&lt;/p&gt;
&lt;p&gt;Il existe certainement d&amp;rsquo;autres possibilités pour optimiser encore ce processus de chargement. Voici celles qui me viennent à l&amp;rsquo;esprit :&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;, si 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 des résultats ?&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Je devrais peut-être me procurer un profileur (&lt;a href="https://xdebug.org/" target="_blank"&gt;Xdebug&lt;/a&gt; ou &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="autres-articles"&gt;Autres articles&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;Cette page a été traduite à l&amp;rsquo;aide de &lt;a href="https://www.deepl.com/fr/translator" target="_blank"&gt;deepl.com&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>MariaDB a détruit le concept du buffer pool configurable dynamiquement !</title><link>https://www.fromdual.com/fr/blog/mariadb-buffer-pool-configurable-dynamiquement-endommage/</link><pubDate>Mon, 09 Feb 2026 19:14:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/blog/mariadb-buffer-pool-configurable-dynamiquement-endommage/</guid><description>&lt;h2 id="description-du-problème"&gt;Description du problème&lt;/h2&gt;
&lt;p&gt;MySQL a introduit le InnoDB buffer pool configurable dynamiquement dans la version 5.7.5 en septembre 2014 (&lt;a href="https://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-5.html" target="_blank"&gt;ici&lt;/a&gt; et &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;ici&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 a repris cette fonctionnalité en septembre 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;Le problème est, d&amp;rsquo;une part, que cette fonctionnalité ne fonctionne plus comme avant et ne fonctionne plus comme prévu. D&amp;rsquo;autre part, ils ont modifié le comportement au printemps 2025 dans le cadre d&amp;rsquo;une série de versions majeures (LTS), ce qui, à mon avis, est absolument inacceptable (&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;De plus, la description à ce sujet est assez maigre (&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;Dans le journal de travail correspondant (&lt;a href="https://jira.mariadb.org/browse/MDEV-36197" target="_blank"&gt;MDEV-36197&lt;/a&gt;), MarkoM décrit également un autre comportement :&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;ce qui, à mon avis, aurait été beaucoup plus judicieux.&lt;/p&gt;
&lt;h2 id="comment-cela-fonctionnait-il-auparavant-"&gt;Comment cela fonctionnait-il auparavant ?&lt;/h2&gt;
&lt;p&gt;Comment cela fonctionnait-il auparavant avec MariaDB et comment cela fonctionne-t-il encore aujourd&amp;rsquo;hui avec 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;Tout est donc OK. Cela fonctionne comme prévu et comme d&amp;rsquo;habitude.&lt;/p&gt;
&lt;h2 id="que-fait-mariadb-aujourdhui-"&gt;Que fait MariaDB aujourd&amp;rsquo;hui ?&lt;/h2&gt;
&lt;p&gt;Que se passe-t-il aujourd&amp;rsquo;hui avec 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;Absolument rien ! Pas même une erreur, juste un avertissement. Et si je ne regarde pas attentivement, je ne remarque même pas que quelque chose n&amp;rsquo;a pas fonctionné.&lt;/p&gt;
&lt;p&gt;Le journal d&amp;rsquo;erreurs MariaDB indique :&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;En cherchant un peu, on découvre que quelque chose a changé ici : &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; et on essaie intuitivement :&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;Mais cela ne fonctionne pas non plus.&lt;/p&gt;
&lt;p&gt;Cela signifie qu&amp;rsquo;il faut redémarrer la base de données ! Et cela peut arriver précisément au moment où l&amp;rsquo;on n&amp;rsquo;a pas besoin de redémarrer et où l&amp;rsquo;on aurait besoin de cette fonctionnalité&amp;hellip;&lt;/p&gt;
&lt;p&gt;La documentation indique également (&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;et (&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;Cela signifie que je dois à nouveau réfléchir à l&amp;rsquo;avance à la taille que je dois donner à &lt;code&gt;innodb_buffer_pool_size_max&lt;/code&gt; et que je ne peux corriger qu&amp;rsquo;après coup, si je l&amp;rsquo;ai oublié ou si je me suis trompé dans mon estimation.&lt;/p&gt;
&lt;p&gt;À mon avis, il s&amp;rsquo;agit d&amp;rsquo;un véritable recul d&amp;rsquo;un point de vue opérationnel. Il s&amp;rsquo;agit probablement d&amp;rsquo;une nouvelle implémentation pour certaines solutions Cloud-only as a Service (Enterprise ?).&lt;/p&gt;
&lt;p&gt;Ma suggestion est la suivante : soit, comme proposé dans MDEV, 0 désactive cette fonctionnalité et le comportement reste inchangé, soit la valeur par défaut est fixée à 75 % de la taille de la RAM, comme le fait &lt;code&gt;innodb_dedicated_server&lt;/code&gt; dans MySQL.&lt;/p&gt;
&lt;p&gt;J&amp;rsquo;ai pris la liberté d&amp;rsquo;ouvrir un bug ici : &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 a gentiment recommandé le lien suivant : &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;. Je ne semble pas être le seul à avoir été contrarié par ce changement&amp;hellip;&lt;/p&gt;
&lt;h2 id="comment-postgresql-procède-t-il-"&gt;Comment PostgreSQL procède-t-il ?&lt;/h2&gt;
&lt;p&gt;PostgreSQL n&amp;rsquo;est actuellement pas (encore) en mesure de modifier dynamiquement les &lt;code&gt;shared_buffers&lt;/code&gt;. La valeur par défaut est généralement de 128 Mo. Ici, la règle générale, similaire à celle de MyISAM, est de 25 à 40 % de la RAM. Cependant, l&amp;rsquo;absence de cette fonctionnalité n&amp;rsquo;est probablement pas si grave dans PostgreSQL, car PostgreSQL s&amp;rsquo;appuie fortement sur le cache du système de fichiers, tout comme 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;h2 id="commentaires"&gt;Commentaires&lt;/h2&gt;
&lt;p&gt;Voir &lt;a href="https://www.fromdual.com/blog/mariadb-dynamically-configurable-buffer-pool-broken/#mariadb-dynamically-configurable-buffer-pool-broken/%23comment-1049"&gt;ici&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Cette page a été traduite à l&amp;rsquo;aide de &lt;a href="https://www.deepl.com/fr/translator" target="_blank"&gt;deepl.com&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Combien d'espace NULL occupe-t-il?</title><link>https://www.fromdual.com/fr/blog/combien-d-espace-null-occupe-t-il/</link><pubDate>Sun, 08 Feb 2026 16:15:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/blog/combien-d-espace-null-occupe-t-il/</guid><description>&lt;p&gt;Lors de ma dernière intervention chez le client, celui-ci est venu me voir, rayonnant de joie, pour me dire qu&amp;rsquo;il avait suivi mon conseil et changé toutes les colonnes de clé primaire de &lt;code&gt;BIGINT&lt;/code&gt; (8 octets) à &lt;code&gt;INT&lt;/code&gt; (4 octets), et que cela avait beaucoup apporté ! Sa base de données MySQL 8.4 avait désormais perdu 750 Go (sur 5,5 To). Super!&lt;/p&gt;
&lt;p&gt;Et oui, je sais que cela contredit les recommandations de certains de mes collègues PostgreSQL (&lt;a href="https://www.crunchydata.com/blog/postgres-serials-should-be-bigint-and-how-to-migrate" target="_blank"&gt;ici&lt;/a&gt; et &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;ici&lt;/a&gt;). Dans le monde MySQL, on accorde plutôt de l&amp;rsquo;importance à ce genre de choses (&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;De plus, InnoDB fonctionne un peu différemment (table clusterée et clé primaire dans toutes les clés secondaires) de PostgreSQL (table heap, index avec pointeur de ligne (&lt;code&gt;ctid&lt;/code&gt;)).&lt;/p&gt;
&lt;p&gt;Mais ce n&amp;rsquo;est pas vraiment le sujet. Immédiatement après, il a demandé si la mise à &lt;code&gt;NULL&lt;/code&gt; des colonnes de type &lt;code&gt;DOUBLE&lt;/code&gt; (8 octets, en langage PostgreSQL &lt;code&gt;DOUBLE PRECISION&lt;/code&gt;) permettrait également de gagner de la place ou s&amp;rsquo;il valait mieux supprimer les colonnes. Ma première réponse instinctive pour &lt;code&gt;DOUBLE&lt;/code&gt; a été: &lt;code&gt;NULL&lt;/code&gt; est utile, suivi de &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; (dans le langage PostgreSQL, &lt;code&gt;VACUUM FULL&lt;/code&gt;). Mais ma deuxième réflexion a été: &lt;code&gt;DOUBLE&lt;/code&gt; est un type de données fixe plus long, est-ce que cela s&amp;rsquo;applique également à &lt;code&gt;NULL&lt;/code&gt; ou seulement aux types de données de longueur variable ? La prudence est mère de sûreté ! Il faut d&amp;rsquo;abord consulter le manuel&amp;hellip;&lt;/p&gt;
&lt;p&gt;Et on y trouve (&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;et (&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="essai-avec-mariadbmysql"&gt;Essai avec MariaDB/MySQL&lt;/h2&gt;
&lt;h3 id="montage-expérimental"&gt;Montage expérimental&lt;/h3&gt;
&lt;p&gt;D&amp;rsquo;une certaine manière, cela me semble un peu trop compliqué. Un petit croquis aiderait peut-être ? Faisons donc un essai:&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;La table atteint une taille d&amp;rsquo;environ 1,8 Go pour 16 millions de lignes, tant dans MariaDB que dans MySQL. Comme ces informations ne sont indiquées que de manière très imprécise dans &lt;code&gt;INFORMATION_SCHEMA&lt;/code&gt;, nous vérifions dans le système de fichiers:&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="défragmentation-du-tableau"&gt;Défragmentation du tableau&lt;/h3&gt;
&lt;p&gt;Nous « défragmentons » ensuite le tableau à l&amp;rsquo;aide de la commande &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt;:&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;: le tableau est copié une fois ! Il faut donc temporairement doubler l&amp;rsquo;espace disque ! Nous pouvons observer cela pendant l&amp;rsquo;exécution de la commande &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt;:&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;Mais le résultat est étonnant ! Avec MariaDB, la taille de la table est restée à peu près la même:&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;Avec MySQL, en revanche, la taille de la table a même augmenté d&amp;rsquo;environ 14 % après la « défragmentation »:&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;Si nous exécutons à nouveau la commande &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt;, la taille reste constante tant avec MariaDB qu&amp;rsquo;avec 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="essai-1-mise-à-null"&gt;Essai 1: mise à &lt;code&gt;NULL&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Nous mettons maintenant les valeurs à &lt;code&gt;NULL&lt;/code&gt;:&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;Après cette étape, la taille des fichiers a même légèrement augmenté:&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;Nous défragmentons ensuite à nouveau la table avec la commande &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt;. Comme prévu, les tables rétrécissent.&lt;/p&gt;
&lt;p&gt;MariaDB (à 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 (à 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;Une nouvelle commande &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; n&amp;rsquo;apporte alors PLUS AUCUN changement dans la taille des fichiers&amp;hellip;&lt;/p&gt;
&lt;h3 id="essai-2-suppression-des-colonnes"&gt;Essai 2: suppression des colonnes&lt;/h3&gt;
&lt;p&gt;Nous essayons maintenant à nouveau avec la commande &lt;code&gt;DROP COLUMN&lt;/code&gt;. La situation de départ est à nouveau la même que celle décrite ci-dessus:&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;Après la commande &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt;, les valeurs sont similaires à celles du premier essai:&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;Une nouvelle commande &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; n&amp;rsquo;apporte également aucun changement supplémentaire, comme ci-dessus:&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;Et maintenant, le deuxième essai avec la suppression des colonnes:&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;Tout d&amp;rsquo;abord, nous constatons que la commande &lt;code&gt;INSTANTANEOUS&lt;/code&gt; n&amp;rsquo;apporte aucune modification aux données, mais uniquement aux métadonnées. D&amp;rsquo;un côté, c&amp;rsquo;est une bonne chose, car l&amp;rsquo;impact sur l&amp;rsquo;application est ainsi réduit au minimum. D&amp;rsquo;un autre côté, cela signifie également qu&amp;rsquo;il n&amp;rsquo;y a pas de gain d&amp;rsquo;espace.&lt;/p&gt;
&lt;p&gt;Nous allons donc à nouveau nous attaquer au problème avec la commande &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;MariaDB (à 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 (à 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;La mise à &lt;code&gt;NULL&lt;/code&gt; des colonnes et la suppression des colonnes permettent toutes deux de gagner beaucoup d&amp;rsquo;espace. La suppression des colonnes permet toutefois de gagner environ 7 % de plus que la mise à &lt;code&gt;NULL&lt;/code&gt;. Si cela est possible au niveau de l&amp;rsquo;application, il convient donc de supprimer les colonnes qui ne sont plus nécessaires ou, si cela n&amp;rsquo;est pas possible, de les mettre à &lt;code&gt;NULL&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="essai-avec-postgresql"&gt;Essai avec PostgreSQL&lt;/h2&gt;
&lt;p&gt;Voyons maintenant ce qu&amp;rsquo;il en est avec PostgreSQL 19devel.&lt;/p&gt;
&lt;h3 id="montage-expérimental-1"&gt;Montage expérimental&lt;/h3&gt;
&lt;p&gt;Le montage expérimental est similaire à celui utilisé pour 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;Commençons par déterminer la taille réelle du tableau. PostgreSQL semble connaître cette information avec une grande précision:&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;Ensuite, nous voulons savoir où se trouvent ces fichiers dans le système de fichiers:&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;Taille des tables et des index dans le système de fichiers:&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; signifie « free space map » (carte de l&amp;rsquo;espace libre)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*_vm&lt;/code&gt; signifie « visibility map » (carte de visibilité)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*.1&lt;/code&gt; signifie 2e segment de l&amp;rsquo;objet (table ou index)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PostgreSQL semble fonctionner par défaut avec des segments de 1 Go et, contrairement à MariaDB/MySQL (&lt;code&gt;INFORMATION_SCHEMA&lt;/code&gt;), connaître très précisément la taille de ses fichiers. Et la différence mentionnée ci-dessus (entre &lt;code&gt;tot_rel_siz&lt;/code&gt; et &lt;code&gt;tab_and_idx_siz&lt;/code&gt;) s&amp;rsquo;explique par les fichiers &lt;code&gt;fsm&lt;/code&gt; et &lt;code&gt;vm&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;équivalent PostgreSQL de la commande &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; de MariaDB/MySQL est la commande &lt;code&gt;VACUUM FULL&lt;/code&gt;:&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;La première chose que l&amp;rsquo;on remarque, c&amp;rsquo;est que PostgreSQL génère beaucoup de fichiers et que le fichier « free space map » a disparu. Contrairement à MariaDB/MySQL, les segments de table sont restés de taille identique. On constate également que l&amp;rsquo;ancienne table a « disparu » (40965, 40970) et qu&amp;rsquo;une nouvelle a été créée (40972 et 40975). La commande &lt;code&gt;VACUUM FULL&lt;/code&gt; de PostgreSQL crée donc également une copie des données, comme dans 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;Pour comprendre quels autres fichiers/objets ont été affectés, la requête suivante est utile:&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="essai-1-mise-à-null-1"&gt;Essai 1: mise à &lt;code&gt;NULL&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Nous mettons également à &lt;code&gt;NULL&lt;/code&gt; les colonnes dans PostgreSQL. Nous n&amp;rsquo;avons plus besoin de consulter le système de fichiers, car PostgreSQL semble connaître précisément la taille des fichiers, comme nous l&amp;rsquo;avons vu ci-dessus:&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;Nous voyons ici que les segments de table augmentent considérablement (+37 %), ce qui est appelé « bloat » dans la terminologie PostgreSQL. L&amp;rsquo;implémentation MVCC de PostgreSQL stocke à la fois l&amp;rsquo;ancienne et la nouvelle version de la ligne « in-place », c&amp;rsquo;est-à-dire directement dans la table, contrairement à MariaDB/MySQL qui stocke l&amp;rsquo;ancienne version dans l&amp;rsquo;espace UNDO et la nouvelle ligne « in-place ». Le fichier d&amp;rsquo;index augmente également de manière significative (+100 %). Nous devons encore approfondir nos recherches pour comprendre pourquoi. De plus, une « carte d&amp;rsquo;espace libre » est à nouveau créée (différence entre &lt;code&gt;tot_rel_siz&lt;/code&gt; et &lt;code&gt;tab_and_idx_siz&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Un &lt;code&gt;VACUUM FULL&lt;/code&gt; réduit ensuite la taille de la table (à 28 %) et de l&amp;rsquo;index (à 50 %) par rapport à leur taille précédente:&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;et par rapport à leur taille d&amp;rsquo;origine, la table (à 38 %) et l&amp;rsquo;index (à 100 %) sont également plus petits. Il reste à déterminer pourquoi l&amp;rsquo;index est resté de la même taille et seule la table a diminué&amp;hellip;&lt;/p&gt;
&lt;h3 id="essai-2-suppression-des-colonnes-1"&gt;Essai 2: suppression des colonnes&lt;/h3&gt;
&lt;p&gt;Les colonnes sont ensuite supprimées à l&amp;rsquo;aide de &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;Comme la réponse a été immédiate, on peut supposer que cette opération est également instantanée. Malheureusement, je n&amp;rsquo;ai rien trouvé à ce sujet dans la documentation PostgreSQL.&lt;/p&gt;
&lt;p&gt;La taille n&amp;rsquo;a pas changé de manière significative, ce qui est normal pour une opération instantanée. Cependant, le fait que la taille n&amp;rsquo;ait pas changé après la commande &lt;code&gt;VACUUM FULL&lt;/code&gt; m&amp;rsquo;a un peu surpris:&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="remarques"&gt;Remarques&lt;/h2&gt;
&lt;p&gt;Le verrouillage dans PostgreSQL fonctionne comme suit:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;VACUUM&lt;/code&gt; Les commandes DML concurrentes sont possibles, comme pour la commande &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt; de MariaDB/MySQL. Le résultat n&amp;rsquo;est toutefois pas tout à fait le même.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VACUUM FULL&lt;/code&gt; provoque un verrouillage &lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt;. Comme pour MariaDB/MySQL 5.5 et versions antérieures avec la commande &lt;code&gt;OPTIMIZE TABLE&lt;/code&gt;. Les commandes DML et &lt;code&gt;SELECT&lt;/code&gt; ne sont PAS autorisées.&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="essais-supplémentaires"&gt;Essais supplémentaires&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Au lieu de &lt;code&gt;0.0&lt;/code&gt;, &lt;code&gt;NULL&lt;/code&gt; a été inséré dans les colonnes &lt;code&gt;d0&lt;/code&gt; à &lt;code&gt;d9&lt;/code&gt;. La table est restée petite (&lt;code&gt;tot_rel_siz_prtty = 1068 Mo&lt;/code&gt;). Il est donc également intéressant d&amp;rsquo;enregistrer &lt;code&gt;NULL&lt;/code&gt; au lieu de valeurs fictives dans PostgreSQL.&lt;/li&gt;
&lt;li&gt;Les colonnes &lt;code&gt;d0&lt;/code&gt; à &lt;code&gt;d9&lt;/code&gt; ont été créées avec &lt;code&gt;DOUBLE PRECISION NOT NULL&lt;/code&gt; et remplies avec les valeurs &lt;code&gt;0.0&lt;/code&gt;. Sans effet: la table est restée volumineuse (&lt;code&gt;tot_rel_siz_prtty = 2232 Mo&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Cette page a été traduite à l&amp;rsquo;aide de &lt;a href="https://www.deepl.com/fr/translator" target="_blank"&gt;deepl.com&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Quelqu'un supprime mes segments de mémoire partagée !</title><link>https://www.fromdual.com/fr/blog/supprime-postgresql-segments-de-memoire-partagee/</link><pubDate>Sun, 08 Feb 2026 06:27:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/blog/supprime-postgresql-segments-de-memoire-partagee/</guid><description>&lt;p&gt;Lorsque nous travaillons avec PostgreSQL sous notre &lt;a href="https://www.fromdual.com/myenv/"&gt;myEnv&lt;/a&gt;, nous obtenons régulièrement des erreurs de segment de mémoire partagée. Exemple:&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;ou nous voyons des messages similaires dans le journal d&amp;rsquo;erreurs PostgreSQL:&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;Comme je suis administrateur MariaDB/MySQL, je ne m&amp;rsquo;y connais pas très bien en matière de problèmes de mémoire partagée (MariaDB/MySQL ne fonctionne pas avec la mémoire partagée). Heureusement, une recherche sur Internet nous a mis sur une piste (&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;). On y trouve la mention suivante:&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="utilisateur-du-système-linux"&gt;Utilisateur du système Linux&lt;/h2&gt;
&lt;p&gt;J&amp;rsquo;ai d&amp;rsquo;abord dû découvrir ce qu&amp;rsquo;était un utilisateur du système sous Linux. J&amp;rsquo;ai trouvé une réponse ici: &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;La norme LSB indique à ce sujet: &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;Sur mon système Ubuntu, cela se présente comme suit:&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;Pour l&amp;rsquo;utilisateur PostgreSQL, cela serait également correct:&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;Mais comme l&amp;rsquo;instance PostgreSQL concernée fonctionne sous notre &lt;a href="https://www.fromdual.com/myenv/"&gt;myEnv&lt;/a&gt;, c&amp;rsquo;est différent:&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;Nous avons donc maintenant deux possibilités:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Nous modifions &lt;code&gt;SYS_UID_MAX&lt;/code&gt; et &lt;code&gt;SYS_GID_MAX&lt;/code&gt; à 1001 (variante simple).&lt;/li&gt;
&lt;li&gt;Ou nous modifions l&amp;rsquo;&lt;code&gt;UID&lt;/code&gt; et le &lt;code&gt;GID&lt;/code&gt; de notre utilisateur &lt;code&gt;dba&lt;/code&gt; à moins de 1000.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="variante-simple-modification-de-sys_uid_max-et-sys_gid_max-à-1001"&gt;Variante simple: modification de &lt;code&gt;SYS_UID_MAX&lt;/code&gt; et &lt;code&gt;SYS_GID_MAX&lt;/code&gt; à 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;Par mesure de sécurité, la machine a été redémarrée. Mais cela n&amp;rsquo;a pas aidé: après peu de temps, les mêmes erreurs réapparaissent.&lt;/p&gt;
&lt;h2 id="variante-plus-compliquée-modification-de-luid-de-1001-à-990"&gt;Variante plus compliquée: Modification de l&amp;rsquo;&lt;code&gt;UID&lt;/code&gt; de 1001 à 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;Pour cela, tous les processus de cet utilisateur doivent être arrêtés!&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;Le problème semble ainsi résolu!&lt;/p&gt;
&lt;h2 id="informations-supplémentaires"&gt;Informations supplémentaires&lt;/h2&gt;
&lt;p&gt;Une source mentionnée plus haut recommandait encore de définir les paramètres suivants dans &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;Cette mesure n&amp;rsquo;est toutefois plus nécessaire, car cela fonctionne également sans cette modification.&lt;/p&gt;
&lt;p&gt;Cette page a été traduite à l&amp;rsquo;aide de &lt;a href="https://www.deepl.com/fr/translator" target="_blank"&gt;deepl.com&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Charger des fichiers CSV dans la base de données</title><link>https://www.fromdual.com/fr/blog/charger-des-fichiers-csv-dans-la-base-de-donnees/</link><pubDate>Fri, 06 Feb 2026 18:04:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/blog/charger-des-fichiers-csv-dans-la-base-de-donnees/</guid><description>&lt;p&gt;Récemment, j&amp;rsquo;ai voulu représenter sur une carte les lieux de résidence des membres de mon association (&lt;a href="https://www.shinguz.ch/computer/gis/igoc-mitglieder/" target="_blank"&gt;membres IGOC&lt;/a&gt;) pour un petit projet personnel. Je connaissais les adresses des membres de l&amp;rsquo;association, mais pas les coordonnées de leurs lieux de résidence.&lt;/p&gt;
&lt;p&gt;Je me suis donc mis à la recherche des coordonnées et j&amp;rsquo;ai trouvé ce que je cherchais auprès de l&amp;rsquo;Office fédéral de topographie (&lt;a href="https://www.swisstopo.admin.ch/fr" target="_blank"&gt;swisstopo&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Les données y sont mises à disposition sous forme de fichier CSV. Détails ici : &lt;a href="https://www.shinguz.ch/computer/gis/schweizer-ortschafts-koordinaten/" target="_blank"&gt;Coordonnées des localités suisses&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Comment charger ces données dans une base de données ?&lt;/p&gt;
&lt;h2 id="chargement-des-données-avec-mariadbmysql"&gt;Chargement des données avec MariaDB/MySQL&lt;/h2&gt;
&lt;p&gt;MariaDB et MySQL disposent pour cela de la commande &lt;code&gt;LOAD DATA INFILE&lt;/code&gt;:&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;On peut ensuite consulter les données dans la base de données:&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;Ou plus précisément :&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;Je laisse le soin au lecteur ou à la lectrice de supprimer les doublons&amp;hellip; :-)&lt;/p&gt;
&lt;p&gt;Jusqu&amp;rsquo;ici tout va bien, passons maintenant aux subtilités:&lt;/p&gt;
&lt;h3 id="différences-entre-mariadb-et-mysql"&gt;Différences entre MariaDB et MySQL&lt;/h3&gt;
&lt;p&gt;La procédure décrite ci-dessus fonctionne parfaitement avec MariaDB 11.4 et 11.8. Avec MySQL 8.4, il existe de légères différences:&lt;/p&gt;
&lt;p&gt;Le premier message d&amp;rsquo;erreur qui empêche le chargement est le suivant:&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;Il peut être contourné assez facilement à l&amp;rsquo;aide de la commande:&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;Lors de la tentative suivante, vous échouerez comme suit:&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;Ce problème peut être résolu en démarrant le client MySQL comme suit:&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="chargement-des-données-avec-postgresql"&gt;Chargement des données avec PostgreSQL&lt;/h2&gt;
&lt;p&gt;PostgreSQL dispose pour cela de la commande &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;Ici aussi, nous obtenons le résultat attendu sous la forme habituelle pour PostgreSQL:&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="petites-différences-entre-mariadbmysql-et-postgresql"&gt;Petites différences entre MariaDB/MySQL et PostgreSQL&lt;/h2&gt;
&lt;p&gt;En principe, la commande de chargement est complètement différente dans les deux univers de bases de données.&lt;/p&gt;
&lt;p&gt;Avec MariaDB et PostgreSQL, les commandes fonctionnent « prêtes à l&amp;rsquo;emploi ». MySQL a intégré deux obstacles de sécurité supplémentaires.&lt;/p&gt;
&lt;p&gt;PostgreSQL ne connaît pas les types de données entières &lt;code&gt;UNSIGNED&lt;/code&gt;, il faut donc utiliser le type de données immédiatement supérieur (&lt;code&gt;INT&lt;/code&gt;), ce qui est un peu moins économe en espace que avec MariaDB/MySQL.&lt;/p&gt;
&lt;h2 id="remarques"&gt;Remarques&lt;/h2&gt;
&lt;p&gt;Lorsque nous avons effectué le même test il y a quelques jours, une erreur s&amp;rsquo;est produite lors du chargement. Il semble donc que la source de données ait également subi une modification minime&amp;hellip;&lt;/p&gt;
&lt;p&gt;Je n&amp;rsquo;ai pas pu déterminer rapidement s&amp;rsquo;il existe une norme SQL pour ces commandes de chargement et, si oui, si MariaDB/MySQL ou PostgreSQL sont conformes à cette norme.&lt;/p&gt;
&lt;p&gt;Et bien sûr, il existe d&amp;rsquo;autres moyens d&amp;rsquo;importer vos données CSV dans la base de données&amp;hellip;&lt;/p&gt;
&lt;p&gt;Les outils &lt;code&gt;mariadb-import&lt;/code&gt;/&lt;code&gt;mysqlimport&lt;/code&gt; sont utilisés si vous souhaitez effectuer cette opération à partir de la ligne de commande. Le moteur de stockage CSV peut également être utilisé à cette fin (pour plus de détails, voir &lt;a href="https://www.fromdual.com/blog/csv-storage-engine/"&gt;ici&lt;/a&gt;). Une variante officiellement prise en charge est le moteur de stockage MariaDB CONNECT avec le type CSV (voir &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;ici&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;Il semblerait que le moteur de stockage CONNECT de MariaDB ne soit malheureusement plus pris en charge? Et l&amp;rsquo;outil &lt;code&gt;mydumper&lt;/code&gt;/&lt;code&gt;myloader&lt;/code&gt; semble également pouvoir traiter les fichiers CSV.&lt;/p&gt;
&lt;p&gt;Et bien sûr, tout cela peut également être résolu de manière applicative&amp;hellip;&lt;/p&gt;
&lt;p&gt;Avec PostgreSQL, les possibilités suivantes existent:&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;puis depuis le 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;Et la variante via le Foreign Data Wrapper (FWD). Mais je ne l&amp;rsquo;ai pas essayée:&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;Le type de données MariaDB/MySQL &lt;code&gt;DOUBLE&lt;/code&gt; s&amp;rsquo;appelle &lt;code&gt;DOUBLE PRECISION&lt;/code&gt; dans PostgreSQL.&lt;/p&gt;
&lt;p&gt;Cette page a été traduite à l&amp;rsquo;aide de &lt;a href="https://www.deepl.com/fr/translator" target="_blank"&gt;deepl.com&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>FromDual</title><link>https://www.fromdual.com/fr/index.php</link><pubDate>Wed, 21 Jan 2026 11:37:08 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/index.php</guid><description>&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;p style="font-size: 20px; text-align: center;"&gt;&lt;strong&gt;Services neutres et indépendants des fabricants&lt;br&gt;
pour MariaDB, Galera Cluster et MySQL !&lt;/strong&gt;&lt;/p&gt;
&lt;br&gt;&lt;br&gt;
&lt;h2 id="services-pour-mariadb-galera-et-mysql"&gt;Services pour MariaDB, Galera et MySQL&lt;/h2&gt;
&lt;p&gt;Nous proposons les &lt;a href="https://www.fromdual.com/fr/nos-services/" title="Services pour MariaDB, Galera et MySQL"&gt;services&lt;/a&gt; suivants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/mariadb-galera-and-mysql-consulting/"&gt;Conseil&lt;/a&gt; neutre et indépendant des fabricants pour MariaDB, Galera Cluster, MySQL et Percona Server.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/mariadb-galera-and-mysql-support/"&gt;Abonnements au support Enterprise&lt;/a&gt; pour MariaDB, Galera Cluster et MySQL.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fromdual.com/mariadb-mysql-training/"&gt;Formations/séminaires&lt;/a&gt; MariaDB, Galera et MySQL pour les administrateurs de bases de données (DBA) et les développeurs.&lt;/li&gt;
&lt;li&gt;Grâce à nos services &lt;a href="https://www.fromdual.com/mariadb-and-mysql-remote-dba/"&gt;remote-DBA&lt;/a&gt;, nous vous aidons à exploiter vos bases de données MariaDB et MySQL critiques pour votre activité.&lt;/li&gt;
&lt;li&gt;Nos produits logiciels : &lt;a href="https://www.fromdual.com/ops-center/"&gt;OpsCenter&lt;/a&gt;, &lt;a href="https://www.fromdual.com/mysql-performance-monitor/"&gt;Performance Monitor&lt;/a&gt;, &lt;a href="https://www.fromdual.com/backup-and-recovery-manager/"&gt;Backup/Recovery Manager&lt;/a&gt; et &lt;a href="https://www.fromdual.com/myenv/"&gt;myEnv&lt;/a&gt; vous assistent dans l&amp;rsquo;exploitation de votre infrastructure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour plus d&amp;rsquo;informations, &lt;a href="https://www.fromdual.com/fr/contact/"&gt;contactez-nous&lt;/a&gt;&amp;hellip;
&lt;br&gt;&lt;/p&gt;
&lt;br&gt;
&lt;fieldset&gt;
&lt;br&gt;
&lt;p style="font-size: 20px; text-align: center;"&gt;&lt;strong&gt;Testez gratuitement notre &lt;a href="https://www.fromdual.com/monitoring-as-a-service-maas"&gt;service de surveillance&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;br&gt;
&lt;/fieldset&gt;
&lt;h2 id="formations-mariadb-galera-et-mysql-prévues"&gt;Formations MariaDB, Galera et MySQL prévues&lt;/h2&gt;
&lt;p&gt;Pour plus d&amp;rsquo;informations sur notre programme de formation continue, consultez la rubrique &lt;a href="https://www.fromdual.com/mariadb-mysql-training/"&gt;Formations/séminaires&lt;/a&gt; MariaDB, Galera et MySQL.
&lt;br&gt;&lt;/p&gt;
&lt;!-- Do NOT move he &lt;br&gt; here otherwise the page will break (500)!!! --&gt;
&lt;?php

$lang = 'en';
$file = '/home/shinguz/www/shinguz/tmp/fromdual_training_snippet_' . $lang . '.html';
if ( file_exists($file) ) {
 readfile($file);
}
else {
 echo '&lt;p style="color: red;"&gt;' . 'ERROR: Snipped currently unavailable!' . '&lt;/p&gt;' . "\n";
 error_log('File: ' . $file . ' does NOT exist.');
}

?&gt;
&lt;h2 id="actualités-fromdual"&gt;Actualités FromDual&lt;/h2&gt;
&lt;p&gt;Pour suivre l&amp;rsquo;actualité de FromDual, suivez-nous sur:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.linkedin.com/company/793494" target="_blank" title="LinkedIn"&gt;LinkedIn&lt;/a&gt;,
&lt;a href="https://x.com/fromdual" target="_blank" title="Twitter"&gt;X / Twitter&lt;/a&gt;,
&lt;a href="https://www.facebook.com/fromdual" target="_blank" title="Facebook"&gt;Facebook&lt;/a&gt;,
&lt;a href="https://bsky.app/profile/fromdual.bsky.social" target="_blank" title="Bluesky"&gt;Bluesky&lt;/a&gt; ou
&lt;a href="https://mastodon.social/@fromdual" target="_blank" title="Mastodon"&gt;Mastodon&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;
Cette page a été traduite avec &lt;a href="https://www.deepl.com/fr/translator" target="_blank"&gt;deepl.com&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Test</title><link>https://www.fromdual.com/fr/test/</link><pubDate>Wed, 21 Jan 2026 11:27:30 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/test/</guid><description>&lt;p&gt;Une page test en allemand&amp;hellip;&lt;/p&gt;</description></item><item><title>Contacter FromDual</title><link>https://www.fromdual.com/fr/contact/</link><pubDate>Fri, 16 Jan 2026 20:42:00 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/contact/</guid><description>&lt;br&gt;
&lt;p&gt;Vous pouvez nous contacter comme suit:&lt;/p&gt;
&lt;br&gt;
&lt;table&gt;
 &lt;colgroup&gt;
 &lt;col style="width: 33%"&gt;
 &lt;col style="width: 33%"&gt;
 &lt;col style="width: 33%"&gt;
 &lt;/colgroup&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td style="width: 192px; vertical-align: top;"&gt;Adresse:&lt;/td&gt;
 &lt;td&gt;FromDual GmbH&lt;br&gt;
 Rebenweg 6&lt;br&gt;
 CH - 8610 &lt;b&gt;Uster&lt;/b&gt;&lt;br&gt;
 Suisse&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;E-mail:&lt;/td&gt;
 &lt;td&gt;&lt;a href="mailto:contact@fromdual.com"&gt;contact@fromdual.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Téléphone:&lt;/td&gt;
 &lt;td&gt;&lt;a href="tel:+41445005820"&gt;+41 44 500 58 20&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;&lt;a href="tel:+492018536770"&gt;+49 201 853 67 70&lt;/a&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&amp;nbsp;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Numéro de TVA/UID:&lt;/td&gt;
 &lt;td&gt;CHE-301.341.221 MWST&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Numéro DUNS:&lt;/td&gt;
 &lt;td&gt;485921436&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;</description></item><item><title>InnoDB deadlock sur SELECT? Pas possible! Ou bien si?</title><link>https://www.fromdual.com/fr/blog/innodb-deadlock-sur-select-pas-possible-ou-bien-si/</link><pubDate>Sat, 25 Nov 2023 17:33:39 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/blog/innodb-deadlock-sur-select-pas-possible-ou-bien-si/</guid><description>&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Deux points pour commencer:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Un deadlock est un état dans lequel deux transactions différentes ne sont plus en mesure de continuer à travailler, car chaque transaction détient un verrou dont l&amp;rsquo;autre transaction aurait besoin. Comme les deux transactions attendent que l&amp;rsquo;autre libère son verrou, aucune des deux transactions ne libérera son verrou. Et cela durerait jusqu&amp;rsquo;à la saint-glinglin. Pour éviter cela, l&amp;rsquo;instance MariaDB intervient et tue rapidement la transaction qui a fait le moins de travail. L&amp;rsquo;application reçoit alors un message d&amp;rsquo;erreur de type &amp;ldquo;deadlock&amp;rdquo;:&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;Dans l&amp;rsquo;écosystème MariaDB, il est généralement admis qu&amp;rsquo;un &lt;code&gt;SELECT&lt;/code&gt; ne provoque pas de verrouillage (exception : &lt;code&gt;FOR UPDATE&lt;/code&gt; ou &lt;code&gt;LOCK IN SHARE MODE&lt;/code&gt;) et ne peut donc pas faire partie d&amp;rsquo;un deadlock.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="le-problème"&gt;Le problème&lt;/h2&gt;
&lt;p&gt;Un client de longue date se présente à l&amp;rsquo;équipe DBA à distance de FromDual en lui demandant d&amp;rsquo;expliquer une situation de deadlock:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Bonjour l&amp;rsquo;équipe FromDual,
J&amp;rsquo;ai à nouveau besoin de votre expertise sur le thème des deadlocks.
Quand cela vous conviendrait-il ?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;La situation est la suivante: La transaction 1 consiste en un simple &lt;code&gt;INSERT&lt;/code&gt;. La transaction 2 consiste en un &lt;code&gt;SELECT&lt;/code&gt;. Cela ne devrait PAS provoquer de blocage.&lt;/p&gt;
&lt;p&gt;Nous vérifions d&amp;rsquo;abord les points suivants:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Toutes les tables concernées par ces requêtes sont-elles correctement indexées? Oui, elles le sont. Les requêtes fonctionnent toutes parfaitement!&lt;/li&gt;
&lt;li&gt;Les requêtes &lt;code&gt;SELECT&lt;/code&gt; font-elles éventuellement partie d&amp;rsquo;une transaction d&amp;rsquo;envergure (transaction NON auto-commit) et ne sont-elles donc pas la cause réelle du blocage? Non, ce n&amp;rsquo;est pas le cas. Il s&amp;rsquo;agit de transactions autocommit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Que faire maintenant? Ce qu&amp;rsquo;il faut encore préciser: Le &lt;code&gt;SELECT&lt;/code&gt; est lancé à une cadence très élevée, c&amp;rsquo;est-à-dire environ toutes les 5 ms!&lt;/p&gt;
&lt;p&gt;Il est évident que l&amp;rsquo;&lt;code&gt;INSERT&lt;/code&gt; génère des verrous. C&amp;rsquo;est d&amp;rsquo;ailleurs affiché. Mais pourquoi l&amp;rsquo;ordre &lt;code&gt;SELECT&lt;/code&gt; génère-t-il des verrous? Ceux-ci sont également affichés!&lt;/p&gt;
&lt;p&gt;Nous essayons donc de résoudre le problème en plusieurs étapes.&lt;/p&gt;
&lt;h2 id="méthode-de-résolution"&gt;Méthode de résolution&lt;/h2&gt;
&lt;p&gt;La requête se présente comme suit:&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;Si nous plaçons cette requête dans une transaction explicite, nous pouvons même voir les verrous :&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;et dans une deuxième connection:&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;Malheureusement, nous ne voyons pas de quel type de verrou (IS) il s&amp;rsquo;agit, car la vue &lt;code&gt;INNODB_LOCKS&lt;/code&gt; est vide.&lt;/p&gt;
&lt;h2 id="la-solution"&gt;La solution&lt;/h2&gt;
&lt;p&gt;Si nous faisons la même tentative avec des SELECT &amp;ldquo;normaux&amp;rdquo;:&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;ou&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;nous ne voyons AUCUN verrouillage:&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;Il semble donc que la construction &lt;code&gt;SET @id = (...)&lt;/code&gt; provoque ce verrou IS. Le client réécrit son application et peu après, nous recevons le message suivant:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Bonjour l&amp;rsquo;équipe FromDual,
Votre conseil était le bon.
Plus de deadlocks depuis vendredi midi.
Merci et bon week-end.&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="autres-questions-résolues"&gt;Autres questions résolues&lt;/h2&gt;
&lt;p&gt;MySQL 8.0 se comporte de la même manière ? Oui, exactement de la même manière.&lt;/p&gt;
&lt;h2 id="addendum"&gt;Addendum&lt;/h2&gt;
&lt;p&gt;Mon cher collègue Matthias m&amp;rsquo;a donné une autre idée de suite: qu&amp;rsquo;en est-il des procédures stockées et des fonctions stockées de MariaDB?&lt;/p&gt;
&lt;p&gt;Les deux tests ici:&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;et ici:&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;
&lt;p&gt;Cette page a été traduite à l&amp;rsquo;aide de &lt;a href="https://www.deepl.com/fr/translator" target="_blank"&gt;deepl.com&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Les blogs FromDual</title><link>https://www.fromdual.com/fr/blog/</link><pubDate>Fri, 26 Mar 2010 10:20:30 +0100</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/blog/</guid><description>&lt;p&gt;Sur cette page, vous trouverez les différents blogs des collaborateurs de FromDual ainsi que quelques agrégats de blogs utiles.&lt;/p&gt;
&lt;h2 id="blogs-des-employés-de-fromdual"&gt;Blogs des employés de FromDual&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.fromdual.com/de/blog/oli/"&gt;Blog d&amp;rsquo;Oli en allemand&lt;/a&gt; &lt;img src="https://www.fromdual.com/images/de.png" alt="german" width="16" height="12"&gt; &lt;a href="https://www.fromdual.com/de/blog/oli/index.xml"&gt;&lt;img src="https://www.fromdual.com/images/feed.png" alt="RSS feed" width="12" height="12"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.fromdual.com/blog/shinguz/"&gt;Blog de Shinguz en anglais&lt;/a&gt; &lt;img src="https://www.fromdual.com/images/en.png" alt="english" width="16" height="12"&gt; &lt;a href="https://www.fromdual.com/blog/shinguz/index.xml"&gt;&lt;img src="https://www.fromdual.com/images/feed.png" alt="RSS feed" width="12" height="12"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.fromdual.com/blog/abdel-mawla/"&gt;Blog d&amp;rsquo;Abdel-Mawla en anglais&lt;/a&gt; &lt;img src="https://www.fromdual.com/images/en.png" alt="english" width="16" height="12"&gt; &lt;a href="https://www.fromdual.com/blog/abdel-mawla/index.xml"&gt;&lt;img src="https://www.fromdual.com/images/feed.png" alt="RSS feed" width="12" height="12"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.fromdual.com/blog/joerg/"&gt;Blog de Jörg en anglais&lt;/a&gt; &lt;img src="https://www.fromdual.com/images/en.png" alt="english" width="16" height="12"&gt; &lt;a href="https://www.fromdual.com/blog/joerg/index.xml"&gt;&lt;img src="https://www.fromdual.com/images/feed.png" alt="RSS feed" width="12" height="12"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.fromdual.com/blog/cedric/"&gt;Blog de Cédric en anglais&lt;/a&gt; &lt;img src="https://www.fromdual.com/images/en.png" alt="english" width="16" height="12"&gt; &lt;a href="https://www.fromdual.com/blog/cedric/index.xml"&gt;&lt;img src="https://www.fromdual.com/images/feed.png" alt="RSS feed" width="12" height="12"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.fromdual.com/de/blog/sales_de/"&gt;Blog commercial de FromDual en allemand&lt;/a&gt; &lt;img src="https://www.fromdual.com/images/de.png" alt="german" width="16" height="12"&gt; &lt;a href="https://www.fromdual.com/de/blog/sales_de/index.xml"&gt;&lt;img src="https://www.fromdual.com/images/feed.png" alt="RSS feed" width="12" height="12"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.fromdual.com/blog/sales_en/"&gt;Blog commercial de FromDual en anglais&lt;/a&gt; &lt;img src="https://www.fromdual.com/images/en.png" alt="english" width="16" height="12"&gt; &lt;a href="https://www.fromdual.com/blog/sales_en/index.xml"&gt;&lt;img src="https://www.fromdual.com/images/feed.png" alt="RSS feed" width="12" height="12"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="agrégateurs-de-blogs-fromdual"&gt;Agrégateurs de blogs FromDual&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.fromdual.com/de/aggregator/categories/10/"&gt;FromDual AllFeed en allemand&lt;/a&gt; &lt;img src="https://www.fromdual.com/images/de.png" alt="german" width="16" height="12"&gt; &lt;a href="https://www.fromdual.com/aggregator/rss/10"&gt;&lt;img src="https://www.fromdual.com/images/feed.png" alt="RSS feed" width="12" height="12"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.fromdual.com/aggregator/categories/9/"&gt;FromDual AllFeed en anglais&lt;/a&gt; &lt;img src="https://www.fromdual.com/images/en.png" alt="english" width="16" height="12"&gt; &lt;a href="https://www.fromdual.com/aggregator/rss/9"&gt;&lt;img src="https://www.fromdual.com/images/feed.png" alt="RSS feed" width="12" height="12"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.fromdual.com/de/aggregator/categories/4/"&gt;FromDual TechFeed en allemand&lt;/a&gt; &lt;img src="https://www.fromdual.com/images/de.png" alt="german" width="16" height="12"&gt; &lt;a href="https://www.fromdual.com/aggregator/rss/4"&gt;&lt;img src="https://www.fromdual.com/images/feed.png" alt="RSS feed" width="12" height="12"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.fromdual.com/aggregator/categories/5/"&gt;FromDual TechFeed en anglais&lt;/a&gt; &lt;img src="https://www.fromdual.com/images/en.png" alt="english" width="16" height="12"&gt; &lt;a href="https://www.fromdual.com/aggregator/rss/5"&gt;&lt;img src="https://www.fromdual.com/images/feed.png" alt="RSS feed" width="12" height="12"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.fromdual.com/de/aggregator/categories/8/"&gt;FromDual InfoFeed en allemand&lt;/a&gt; &lt;img src="https://www.fromdual.com/images/de.png" alt="german" width="16" height="12"&gt; &lt;a href="https://www.fromdual.com/aggregator/rss/8"&gt;&lt;img src="https://www.fromdual.com/images/feed.png" alt="RSS feed" width="12" height="12"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.fromdual.com/aggregator/categories/6/"&gt;FromDual InfoFeed en anglais&lt;/a&gt; &lt;img src="https://www.fromdual.com/images/en.png" alt="english" width="16" height="12"&gt; &lt;a href="https://www.fromdual.com/aggregator/rss/6"&gt;&lt;img src="https://www.fromdual.com/images/feed.png" alt="RSS feed" width="12" height="12"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;MySQL Tech-Feed en allemand &lt;img src="https://www.fromdual.com/images/de.png" alt="german" width="16" height="12"&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.fromdual.com/aggregator/categories/3/"&gt;MySQL Tech-Feed en anglais&lt;/a&gt; &lt;img src="https://www.fromdual.com/images/en.png" alt="english" width="16" height="12"&gt; &lt;a href="https://www.fromdual.com/aggregator/rss/3"&gt;&lt;img src="https://www.fromdual.com/images/feed.png" alt="RSS feed" width="12" height="12"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PostgreSQL Tech-Feed en allemand &lt;img src="https://www.fromdual.com/images/de.png" alt="german" width="16" height="12"&gt;&lt;/p&gt;
&lt;p&gt;PostgreSQL Tech-Feed en anglais &lt;img src="https://www.fromdual.com/images/en.png" alt="english" width="16" height="12"&gt;&lt;/p&gt;
&lt;p&gt;&lt;br&gt;&lt;br&gt;
Cette page a été traduite avec &lt;a href="https://www.deepl.com/fr/translator" target="_blank"&gt;deepl.com&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Oups! Page introuvable.</title><link>https://www.fromdual.com/fr/404/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/404/</guid><description>&lt;br&gt;
&lt;br&gt;
&lt;p&gt;Que cherches-tu exactement?&lt;/p&gt;
&lt;br&gt;
&lt;link href="https://www.fromdual.com/pagefind/pagefind-ui.css" rel="stylesheet"&gt;
&lt;script src="https://www.fromdual.com/pagefind/pagefind-ui.js"&gt;&lt;/script&gt;
&lt;div id="looking-for"&gt;&lt;/div&gt;
&lt;script&gt;
 window.addEventListener('DOMContentLoaded', (event) =&gt; {
 new PagefindUI({ element: "#looking-for", showSubResults: true });
 });
&lt;/script&gt;</description></item><item><title/><link>https://www.fromdual.com/fr/nos-services/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/nos-services/</guid><description/></item><item><title/><link>https://www.fromdual.com/fr/blog/shinguz/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/blog/shinguz/</guid><description/></item><item><title/><link>https://www.fromdual.com/fr/blog/sales_en/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/blog/sales_en/</guid><description/></item><item><title/><link>https://www.fromdual.com/fr/blog/sales_de/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/blog/sales_de/</guid><description/></item><item><title/><link>https://www.fromdual.com/fr/blog/oli/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/blog/oli/</guid><description/></item><item><title/><link>https://www.fromdual.com/fr/blog/joerg/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/blog/joerg/</guid><description/></item><item><title/><link>https://www.fromdual.com/fr/blog/cedric/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/blog/cedric/</guid><description/></item><item><title/><link>https://www.fromdual.com/fr/blog/abdel-mawla/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><author>oli.sennhauser@fromdual.com (Oli Sennhauser)</author><guid>https://www.fromdual.com/fr/blog/abdel-mawla/</guid><description/></item></channel></rss>