web-dev-qa-db-ja.com

削除する行を識別するためのシステム列「ctid」は合法ですか?

データを削除する必要のある数億行のテーブルがあります。

既存のインデックスが最も効率的です。

ただし、既存のインデックスを使用して、ctid値を使用することにより、削除する行を見つけることができます。

DELETE FROM calendar_event WHERE ctid IN
(SELECT ctid FROM calendar_event WHERE user_id = 5 LIMIT 100 FOR UPDATE)

この場合、ctidに依存するリスクは何ですか?私の最悪のシナリオは、間違った行を削除することです。

6
ruelloehr

ROW SHAREが取得するFOR UPDATEロックは、行の物理的な場所を変更する同時書き込みアクセスを防ぎます。 マニュアル:

これにより、現在のトランザクションが終了するまで、他のトランザクションによってロック、変更、または削除されるのを防ぎます。つまり、これらの行のUPDATEDELETESELECT FOR UPDATESELECT FOR NO KEY UPDATESELECT 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について:

7