私はいくつかのテストを実行しました。EXISTS
バリアントはかなり高速であることがわかります-私が予想したように、@Tometzkyが投稿したものとは反対です。
適切な設定でPostgreSQL9.1.2の10.000行のテストベッド:
CREATE TEMP TABLE test (
a serial
,b int NOT NULL
,c int NOT NULL
);
INSERT INTO test (b,c)
SELECT (random()* 100)::int AS b, (random()* 100)::int AS c
FROM generate_series(1, 10000);
ALTER TABLE test ADD CONSTRAINT a_pk PRIMARY KEY (a);
テストの第1ラウンドと第2ラウンドの間に、次のコマンドを実行しました。
ANALYZE test;
最終的にDELETEを適用すると、3368個の重複が削除されました。重複が大幅に多い場合や少ない場合は、パフォーマンスが異なる場合があります。
で各クエリを数回実行しEXPLAIN ANALYZE
、最良の結果を得ました。一般的に、最良のものは最初のものまたは最悪のものとほとんど変わりません。
裸SELECT
(なしDELETE
)でも同様の結果が得られます。
1.CTEとrank()
合計実行時間:150.411ミリ秒
合計実行時間:149.853ミリ秒-ANALYZE後
WITH x AS (
SELECT a
,rank() OVER (PARTITION BY b, c ORDER BY a) AS rk
FROM test
)
DELETE FROM test
USING x
WHERE x.a = test.a
AND rk > 1;
2.CTEとrow_number()
合計実行時間:148.240ミリ秒
合計実行時間:147.711ミリ秒-ANALYZE後
WITH x AS (
SELECT a
,row_number() OVER (PARTITION BY b, c ORDER BY a) AS rn
FROM test
)
DELETE FROM test
USING x
WHERE x.a = test.a
AND rn > 1;
3.row_number()
サブクエリで
合計実行時間:134.753ミリ秒
合計実行時間:134.298ミリ秒-ANALYZE後
DELETE FROM test
USING (
SELECT a
,row_number() OVER (PARTITION BY b, c ORDER BY a) AS rn
FROM test
) x
WHERE x.a = test.a
AND rn > 1;
4.EXISTS
セミジョイン
合計実行時間:143.777ミリ秒
合計実行時間:69.072ミリ秒-ANALYZE 後
DELETE FROM test t
WHERE EXISTS (
SELECT 1
FROM test t1
WHERE t1.a < t.a
AND (t1.b, t1.c) = (t.b, t.c)
);
2回目の実行での違いは、追加のソート+マージセミジョインではなく、ハッシュセミジョインに切り替えることです。
結果
EXISTS
明らかにup-tp-dateテーブル統計で勝ちます。
- サブクエリに古い統計
row_number()
があると、最速になります。
rank()
最も遅いバリアントです。
- CTEはサブクエリよりも低速です。
ANALYZE
(更新された統計)はパフォーマンスを助け、大いに役立ちます。Autovacuum(デフォルト)は、一時的なテーブルまたはテーブルへの大きな変更の直後を除いて、多かれ少なかれこれを自動的に処理する必要があります。詳細はこちらまたはこちらをご覧ください。
100.000行でテストする
100.000行と63045の複製でテストを繰り返しました。EXISTS
後でも遅いことを除いて、同様の結果ANALYZE
。
- 総実行時間:1648.601ミリ秒
- 総実行時間:1623.759ミリ秒
- 総実行時間:1568.893ミリ秒
- 総実行時間:1692.249ミリ秒
統計ターゲットを1000に上げてから最大10000(実際のライブではやり過ぎ)に上げると、別ANALYZE
のクエリはすべてのクエリを最大1%高速化しましたが、クエリプランナーは引き続きSort + Merge SemiJoinforを使用しましEXISTS
た。
ALTER TABLE test ALTER COLUMN b SET STATISTICS 10000;
ALTER TABLE test ALTER COLUMN c SET STATISTICS 10000;
ANALYZE test;
マージ結合を回避するようにプランナーに強制した後でのみ、プランナーはハッシュセミ結合を使用して再び半分の時間を費やしました。
SET enable_mergejoin = off
- 総実行時間:850.615ミリ秒
アップデート
それ以来、クエリプランナーが改善されています。PostgreSQL9.1.7を使用した再テストでHashSemiJoinに直接移動しました。