J'exécute des requêtes Postgres simultanées comme ceci:
UPDATE foo SET bar = bar + 1 WHERE baz = 1234
Chaque requête affecte le nombre K fixe de lignes, et je ne peux pas trouver un moyen d'appliquer l'ordre dans lequel les lignes sont mises à jour, je me retrouve avec des blocages. Actuellement, je résout le problème en appliquant l'ordre manuellement, mais cela signifie que je dois exécuter beaucoup plus de requêtes que je ne le ferais normalement tout en augmentant la complexité de la recherche de O (log N + K) à O (K log N).
Existe-t-il un moyen d'améliorer les performances sans se retrouver vulnérable aux blocages? Je soupçonne que le remplacement de l' (baz)
index par l' (baz, id)
index pourrait fonctionner à condition que Postgres mette à jour les lignes dans le même ordre qu'il les a scannées, est-ce une approche qui mérite d'être poursuivie?
la source
CREATE TABLE
code.Réponses:
Il n'y
ORDER BY
en a pas dans uneSQL UPDATE
commande. Postgres met à jour les lignes dans un ordre arbitraire:Pour éviter les blocages avec une certitude absolue, vous pouvez exécuter vos instructions dans une isolation de transaction sérialisable . Mais c'est plus cher et vous devez vous préparer à répéter les commandes en cas d'échec de la sérialisation.
Votre meilleure solution consiste probablement à verrouiller explicitement avec
SELECT ... ORDER BY ... FOR UPDATE
dans une sous-requête ou de manière autonomeSELECT
dans une transaction - par défaut, en niveau d'isolement "lecture validée". Citant Tom Lane sur pgsql-general :Cela devrait faire le travail:
Un index multicolonne sur
(baz, bar)
pourrait être parfait pour les performances. Mais comme ilbar
est évidemment beaucoup mis à jour , un index sur une seule colonne(baz)
pourrait être encore mieux. Cela dépend de quelques facteurs. Combien de lignes parbaz
? Les mises à jour HOT sont-elles possibles sans l'index multicolonne? ...Si
baz
est mis à jour simultanément, il y a toujours une chance improbable de cas de coin pour les conflits (par documentation) :En outre, si vous devez avoir une contrainte unique impliquant
bar
, envisagez uneDEFERRABLE
contrainte pour éviter les violations uniques au sein de la même commande. Réponse connexe:la source
id
ou une autre colonne unique au lieu debar
, il ne devrait pas y avoir de cas d'angle ou de performance, non?