Pour tous ceux qui recherchent sur Google et essaient de comprendre pourquoi leur table de dépôt (ou leur clé étrangère ou leur ajout de clé étrangère) est restée bloquée pendant longtemps :
PostgreSQL (J'ai regardé les versions 9.4 à 13) les contraintes de clé étrangère sont en fait implémentées à l'aide de déclencheurs aux deux extrémités de la clé étrangère .
Si vous avez une table company (id comme clé primaire) et une table bank_account (id comme clé primaire, company_id comme clé étrangère pointant vers company.id), alors il y a en fait 2 déclencheurs sur la table bank_account et aussi 2 déclencheurs sur la société tableau.
table_name | délai | nom_déclencheur | nom_fonction |
---|---|---|---|
bank_account | APRÈS LA MISE À JOUR | RI_ConstraintTrigger_c_1515961 | RI_FKey_check_upd |
compte_bancaire | APRÈS INSÉRER | RI_ConstraintTrigger_c_1515960 | RI_FKey_check_ins |
entreprise | APRÈS LA MISE À JOUR | RI_ConstraintTrigger_a_1515959 | RI_FKey_noaction_upd |
entreprise | APRÈS SUPPRESSION | RI_ConstraintTrigger_a_1515958 | RI_FKey_noaction_del |
La création initiale de ces déclencheurs (lors de la création de la clé foreing) nécessite un verrou SHARE ROW EXCLUSIVE sur ces tables (il s'agissait auparavant du verrou ACCESS EXCLUSIVE dans la version 9.4 et les versions antérieures). Ce verrou n'entre pas en conflit avec les "verrous de lecture de données", mais entrera en conflit avec tous les autres verrous, par exemple un simple INSERT/UPDATE/DELETE dans la table de l'entreprise.
La suppression de ces déclencheurs (lors de la suppression de la clé étrangère ou de la table entière) nécessite un verrou ACCESS EXCLUSIVE sur ces tables. Ce verrou est en conflit avec tous les autres verrous !
Imaginez donc un scénario dans lequel vous avez une transaction A en cours d'exécution qui a d'abord effectué un simple SELECT à partir de la table de l'entreprise (l'amenant à maintenir un verrou ACCESS SHARE pour la table de l'entreprise jusqu'à ce que la transaction soit validée ou annulée) et effectue maintenant un autre travail pour 3 minutes. Vous essayez de supprimer la table bank_account dans la transaction B. Cela nécessite le verrou ACCESS EXCLUSIVE, qui devra attendre que le verrou ACCESS SHARE soit d'abord libéré. ou peut-être INSERT/UPDATE/DELETE), sera mis en file d'attente pour attendre le verrou ACCESS EXCLUSIVE, qui attend le verrou ACCESS SHARE.
Les transactions de longue durée et les modifications DDL nécessitent une manipulation délicate.