Je dois mettre à jour des tables de 1 ou 2 milliards de lignes avec différentes valeurs pour chaque ligne. Chaque exécution fait environ 100 millions de modifications (10 %). Mon premier essai a été de les regrouper en transaction de 300 000 mises à jour directement sur une partition spécifique, car Postgresql n'optimise pas toujours les requêtes préparées si vous utilisez des partitions.
- Transactions d'un groupe de "UPDATE myTable SET myField=value WHEREmyId=id"
Donne 1 500 mises à jour/sec. ce qui signifie que chaque exécution prendrait au moins 18 heures. - Solution de mises à jour HOT comme décrit ici avec FILLFACTOR=50. Donne 1 600 mises à jour/sec. J'utilise des SSD, c'est donc une amélioration coûteuse car elle double la taille de stockage.
- Insérer dans une table temporaire des valeurs mises à jour et les fusionner ensuite avec UPDATE...FROM Donne 18 000 mises à jour/sec. si je fais un VACUUMpour chaque partition; 100 000 up/s sinon. Cooool.
Voici la suite des opérations :
CREATE TEMP TABLE tempTable (id BIGINT NOT NULL, field(s) to be updated,
CONSTRAINT tempTable_pkey PRIMARY KEY (id));
Accumulez un tas de mises à jour dans un tampon en fonction de la RAM disponible. Lorsqu'il est rempli, ou qu'il faut changer de table/partition, ou qu'il est terminé :
COPY tempTable FROM buffer;
UPDATE myTable a SET field(s)=value(s) FROM tempTable b WHERE a.id=b.id;
COMMIT;
TRUNCATE TABLE tempTable;
VACUUM FULL ANALYZE myTable;
Cela signifie qu'une exécution prend désormais 1h30 au lieu de 18h pour 100 millions de mises à jour, vide inclus. Pour gagner du temps, il n'est pas nécessaire de faire un vide FULL à la fin mais même un vide régulier rapide est utile pour contrôler votre ID de transaction sur la base de données et ne pas obtenir de vide automatique indésirable pendant les heures de pointe.