Je suis donc confus au sujet de la gestion des contraintes de clé étrangère dans Postgresql. (version 8.4.4, pour ce que ça vaut).Postgresql: Acquisition de verrou implicite à partir d'une évaluation de contrainte de clé étrangère
Nous avons deux tables, légèrement anonymisées ci-dessous:
device:
(id, blah, blah, blah, blah, blah x 50)…
primary key on id
whooooole bunch of other junk
device_foo:
(id, device_id, left, right)
Foreign key (device_id) references device(id) on delete cascade;
primary key on id
btree index on 'left' and 'right'
Je me suis donc avec deux fenêtres de base de données pour exécuter certaines requêtes.
db1> begin; lock table device in exclusive mode;
db2> begin; update device_foo set left = left + 1;
Les blocs de connexion db2.
Il me semble étrange qu'une mise à jour de la colonne 'left' sur device_stuff soit affectée par l'activité sur la table de périphériques. Mais il est. En fait, si je reviens à DB1:
db1> select * from device_stuff for update;
*** deadlock occurs ***
Le journal des pgsql a les éléments suivants:
blah blah blah deadlock blah.
CONTEXT: SQL statement "SELECT 1 FROM ONLY "public"."device" x WHERE "id" OPERATOR(pg_catalog.=) $1 FOR SHARE OF X: update device_foo set left = left + 1;
Je suppose que j'ai deux questions: la première est que je ne comprends pas la mécanisme précis par lequel ce genre de verrouillage se produit. J'ai quelques requêtes utiles pour interroger pg_locks pour voir quel genre de verrous une instruction invoque, mais je n'ai pas été en mesure d'observer ce genre particulier de verrouillage lorsque j'exécute la commande update device_foo
en isolation. (Peut-être que je fais quelque chose de mal, cependant.) Je ne peux pas non plus trouver de documentation sur le comportement d'acquisition de verrous des contrôles de contraintes de clé étrangère. Tout ce que j'ai est un message de journal. Dois-je en déduire que toute modification apportée à une ligne va acquérir un verrou de mise à jour sur toutes les tables contre lesquelles elle est importée?
Le deuxième problème est que je voudrais trouver un moyen de faire en sorte que cela n'arrive pas comme ça. Je me retrouve avec des blocages occasionnels dans l'application actuelle. Je voudrais être en mesure d'exécuter de grandes instructions de mise à jour qui affectent toutes les lignes sur device_foo
sans acquérir un grand verrou sur la table des périphériques. (Il y a un beaucoup d'accès en cours dans la table device
, et il est en quelque sorte un verrou coûteux à obtenir.)
Mais pourquoi doit-il vérifier les contraintes de clé étrangère? Je ne change aucune colonne de clé étrangère. – fennec