データを削除する必要のある数億行のテーブルがあります。
既存のインデックスが最も効率的です。
ただし、既存のインデックスを使用して、ctid
値を使用することにより、削除する行を見つけることができます。
DELETE FROM calendar_event WHERE ctid IN
(SELECT ctid FROM calendar_event WHERE user_id = 5 LIMIT 100 FOR UPDATE)
この場合、ctid
に依存するリスクは何ですか?私の最悪のシナリオは、間違った行を削除することです。
ROW SHARE
が取得するFOR UPDATE
ロックは、行の物理的な場所を変更する同時書き込みアクセスを防ぎます。 マニュアル:
これにより、現在のトランザクションが終了するまで、他のトランザクションによってロック、変更、または削除されるのを防ぎます。つまり、これらの行の
UPDATE
、DELETE
、SELECT FOR UPDATE
、SELECT FOR NO KEY UPDATE
、SELECT FOR SHARE
またはSELECT FOR KEY SHARE
を試行する他のトランザクションはブロックされます現在のトランザクションが終了するまで。
したがって、同じトランザクション内の行を自分で変更しない限り、ctid
はコマンド(またはトランザクションであっても)の期間中安定している必要があります。 ctid
は引き続き内部使用のためのシステム列であり、プロジェクトは保証を提供しません。 any一意の(組み合わせ)列(PKを含む)がある場合は、ctid
の代わりにそれを使用します。
ただし、CTEを使用して選択を具体化し、予期しない結果を回避します。
そしてORDER BY
なしでは、削除する任意の行を選択します。 SKIP LOCKED
を追加して、同時トランザクションとのロック競合を最小限に抑えることもできます。
WITH cte AS (
SELECT ctid
FROM calendar_event
WHERE user_id = 5
LIMIT 100
FOR UPDATE SKIP LOCKED
)
DELETE FROM calendar_event WHERE ctid IN (TABLE cte);
関連、両方の考慮事項のexplanationを使用:
ctid
について: