グーグルして、ドロップテーブル(または外部キーをドロップするか外部キーを追加する)が長い間スタックした理由を理解しようとしている人のために:
PostgreSQL (バージョン9.4から13を見ました)外部キー制約は、実際には外部キーの両端のトリガーを使用して実装されています 。
companyテーブル(主キーとしてのid)とbank_accountテーブル(主キーとしてのid、company.idを指す外部キーとしてのcompany_id)がある場合、実際には、bank_accountテーブルに2つのトリガーがあり、会社にも2つのトリガーがあります。テーブル。
table_name | タイミング | trigger_name | function_name |
---|---|---|---|
bank_account | 更新後 | RI_ConstraintTrigger_c_1515961 | RI_FKey_check_upd |
bank_account | 挿入後 | RI_ConstraintTrigger_c_1515960 | RI_FKey_check_ins |
会社 | 更新後 | RI_ConstraintTrigger_a_1515959 | RI_FKey_noaction_upd |
会社 | 削除後 | RI_ConstraintTrigger_a_1515958 | RI_FKey_noaction_del |
これらのトリガーの最初の作成(主キーの作成時)には、これらのテーブルに対するSHARE ROW EXCLUSIVEロックが必要です(バージョン9.4以前ではACCESS EXCLUSIVEロックでした)。このロックは「データ読み取りロック」と競合しませんが、他のすべてのロック、たとえば会社のテーブルへの単純なINSERT / UPDATE/DELETEと競合します。
これらのトリガーを削除するには(外部キーまたはテーブル全体をドロップする場合)、これらのテーブルでACCESSEXCLUSIVEロックが必要です。このロックは他のすべてのロックと競合します!
したがって、最初に会社のテーブルから単純なSELECTを実行し(トランザクションがコミットまたはロールバックされるまで会社のテーブルのACCESS SHAREロックを保持する)トランザクションAを実行し、現在は他の作業を行っているシナリオを想像してみてください。 3分。トランザクションBでbank_accountテーブルを削除しようとしました。これにはACCESSEXCLUSIVEロックが必要であり、最初にACCESS SHAREロックが解放されるまで待機する必要があります。さらに、companyテーブルにアクセスする他のすべてのトランザクション(SELECT、または、INSERT / UPDATE / DELETE)は、ACCESSSHAREロックを待機しているACCESSEXCLUSIVEロックを待機するためにキューに入れられます。
長時間実行されるトランザクションとDDLの変更には、慎重な処理が必要です。