Utiliser PG 9.1 sur Ubuntu 12.04.
Il nous faut actuellement jusqu'à 24 heures pour exécuter un grand nombre d'instructions UPDATE sur une base de données, qui se présente sous la forme:
UPDATE table
SET field1 = constant1, field2 = constant2, ...
WHERE id = constid
(Nous ne faisons que remplacer des champs d'objets identifiés par un ID.) Les valeurs proviennent d'une source de données externe (pas déjà dans le DB dans une table).
Les tables ont des poignées d'indices chacune et aucune contrainte de clé étrangère. Aucun engagement n'est fait jusqu'à la fin.
Il faut 2h pour importer une partie pg_dump
de la base de données. Cela semble être une base de référence que nous devrions raisonnablement cibler.
Mis à part la production d'un programme personnalisé qui reconstruit en quelque sorte un ensemble de données que PostgreSQL peut réimporter, pouvons-nous faire quelque chose pour rapprocher les performances UPDATE en bloc de celles de l'importation? (C’est un domaine que nous pensons être bien géré par les arbres de fusion logarithmiques, mais nous nous demandons s’il est possible de faire quelque chose dans PostgreSQL.)
Quelques idées:
- abandonner tous les index non-ID et reconstruire ensuite?
- checkpoint_segments croissants, mais cela aide-t-il réellement à un débit soutenu à long terme?
- en utilisant les techniques mentionnées ici ? (Charger les nouvelles données sous forme de table, puis "fusionner" les anciennes données sans identifiant)
Fondamentalement, il y a beaucoup de choses à essayer et nous ne savons pas ce qui est le plus efficace ou si nous négligeons d'autres choses. Nous allons passer les prochains jours à expérimenter, mais nous pensions pouvoir le faire ici aussi.
J'ai une charge simultanée sur la table mais elle est en lecture seule.
explain analyze
l'utilisation d'un index pour la recherche?Réponses:
Hypothèses
Comme il manque des informations dans le Q, je suppose:
COPY
sortie, avec un numéro uniqueid
par ligne correspondant à la table cible.Sinon, formatez-le correctement en premier ou utilisez les
COPY
options pour gérer le format.Cela signifie pas d' accès simultané. Sinon, considérez cette réponse:
Solution
Je suggère que vous adoptiez une approche similaire à celle décrite au lien de votre troisième puce . Avec des optimisations majeures.
Pour créer la table temporaire, il existe un moyen plus simple et plus rapide:
Une seule grande
UPDATE
d'une table temporaire dans la base de données sera plus rapide que les mises à jour individuelles de l'extérieur de la base de données de plusieurs ordres de grandeur.Dans le modèle MVCC de PostgreSQL , un
UPDATE
moyen de créer une nouvelle version de ligne et de marquer l'ancienne comme étant supprimée. C'est à peu près aussi cher qu'unINSERT
et unDELETE
combiné. De plus, il vous laisse beaucoup de tuples morts. De toute façon, comme vous mettez à jour toute la table, il serait plus rapide de simplement créer une nouvelle table et de supprimer l’ancienne.Si vous avez assez de RAM disponible, définissez
temp_buffers
(uniquement pour cette session!) Suffisamment haut pour contenir la table temporaire en RAM - avant toute chose.Pour obtenir une estimation de la quantité de RAM nécessaire, exécutez un test avec un petit échantillon et utilisez les fonctions de taille d'objet db :
Script complet
Charge simultanée
Les opérations simultanées sur la table (que j’avais exclues dans les hypothèses au début) attendent, une fois que la table est verrouillée près de la fin et échouent dès que la transaction est validée, car le nom de la table est résolu immédiatement en OID, mais la nouvelle table a un OID différent. La table reste cohérente, mais les opérations simultanées peuvent faire l'objet d'une exception et doivent être répétées. Détails dans cette réponse:
UPDATE route
Si vous devez (suivre) la
UPDATE
route, supprimez tout index non nécessaire lors de la mise à jour, puis recréez-le. Il est beaucoup moins coûteux de créer un index en un seul morceau que de le mettre à jour pour chaque ligne. Cela peut également permettre des mises à jour HOT .J'ai décrit une procédure similaire en utilisant
UPDATE
dans cette réponse étroitement liée sur SO .la source
DROP TABLE
en sort uneAccess Exclusive Lock
. Quoi qu'il en soit, j'ai déjà énuméré les conditions préalables en haut de ma réponse:You can afford to drop and recreate the target table.
il pourrait être utile de verrouiller la table au début de la transaction. Je vous suggère de commencer une nouvelle question avec tous les détails pertinents de votre situation afin que nous puissions aller au fond des choses.CREATE TABLE tbl_new AS SELECT t.*, u.field1, u.field2 from tbl t NATURAL LEFT JOIN tmp_tbl u;
, enLEFT JOIN
permettant de conserver les lignes pour lesquelles il n'y a pas de mise à jour. Bien sûr, leNATURAL
peut être changé en tout valideUSING()
ouON
.Si les données peuvent être rendues disponibles dans un fichier structuré, vous pouvez les lire avec un wrapper de données étrangères et effectuer une fusion sur la table cible.
la source
MERGE
n'est pas encore implémenté dans PostgreSQL . Les implémentations dans d'autres SGBDR varient un peu. Considérons les informations de balise pourMERGE
etUPSERT
.