web-dev-qa-db-ja.com

不確実性の下でのCTE実行順序の管理

パフォーマンス上の理由 のために、大規模なマルチステップCTEを書いています。

1つのクエリでは、データをあるテーブルから別のテーブルに移動する必要がありますが、移動される行の数は不確かであり、ゼロになる場合があります。

後続のテーブルでは、前のクエリからのOriginが削除されますが、前のクエリが完了した後である必要があります。

最後に、上記の2番目のクエリが完了した後、削除された行の代わりに行を書き込む必要があります。

最初の2つのクエリでは、RETURNINGを使用して実行順序を強制しています。

2番目のクエリでは、最初のクエリがこのサブクエリによって完了すると判断しています

(SELECT COUNT(*) FROM first_query) >= 0

3番目のクエリでは、2番目のクエリがこのサブクエリによって完了すると判断しています

SELECT EXISTS (SELECT 1 FROM second_query)

サブクエリは、最初のクエリが完了したことを確認するためのものですか?

サブクエリは、行を返す必要のある2番目のクエリが正確性、精度、およびパフォーマンスに関して最適化されていることを確認するためのものですか?

上記のサブクエリを使用して実行順序を強制すると、キー値の重複違反が発生します。

クエリサブセクション

WITH copy_to_other_table AS (
    INSERT INTO other_table (column_a, column_b) 
        SELECT column_a, column_b 
            FROM main_table
        WHERE column_a = $1::bigint
        RETURNING *
),
main_table_deleted AS (
    DELETE FROM main_table WHERE column_a = $1::bigint 
        AND (SELECT COUNT(*) FROM copy_to_other_table) >= 0         
        RETURNING *
)
INSERT INTO main_table (column_a, column_b) 
        SELECT column_a, column_b 
            FROM another_table WHERE column_a = $1::bigint 
             AND EXISTS (SELECT 1 FROM main_table_deleted) 

一意性制約に違反しているのは、最後のクエリです。

5
Jim Bob

Ypercubeが引用した同じページから、これが問題の原因であると思われます。

1つのステートメントで同じ行を2回更新することはサポートされていません。変更は1つだけ行われますが、どの変更を確実に予測することは簡単ではありません(場合によっては不可能です)。これは、同じステートメントで既に更新された行の削除にも適用されます。更新のみが実行されます。したがって、通常、1つのステートメントで1つの行を2回変更することは避けてください。特に、メインステートメントまたは兄弟サブステートメントによって変更された同じ行に影響を与える可能性のあるWITHサブステートメントの記述は避けてください。このような声明の影響は予測できません。

制約

より複雑なクエリをテストすると、サブステートメントレベルで一意の制約が適用され、ステートメントレベルで外部キーが適用されているように見えます。

6
Jim Bob