sja*_*ski 4 sql postgresql performance unique duplicate-removal
我想在对两列放置唯一约束之前清理表中的一些数据.
CREATE TABLE test (
a integer NOT NULL,
b integer NOT NULL,
c integer NOT NULL,
CONSTRAINT a_pk PRIMARY KEY (a)
);
INSERT INTO test (a,b,c) VALUES
(1,2,3)
,(2,2,3)
,(3,4,3)
,(4,4,4)
,(5,4,5)
,(6,4,4)
,(7,4,4);
-- SELECT a FROM test WHERE ????
Run Code Online (Sandbox Code Playgroud)
输出应该是 2,6,7
我正在寻找第一个重复之后的所有行b,c
EX:
第1,2行有(2,3)为b,c第1行是可以的,因为它是第一个,2不是.
第4,6,7行有(4,4)为b,c第4行是可以的,因为它是第一个,6,7不是.
然后我会:
DELETE FROM test WHERE a = those IDs;
Run Code Online (Sandbox Code Playgroud)
..并添加唯一约束.
我正在考虑与自己进行测试相交,但不确定从那里开始做什么.
我做了几个测试.EXISTS事实证明,该变体要快得多 - 正如我所预料的那样,与@Tometzky所发布的相反.
PostgreSQL 9.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);
Run Code Online (Sandbox Code Playgroud)
在第一轮和第二轮测试之间,我跑了:
ANALYZE test;
Run Code Online (Sandbox Code Playgroud)
当我最终应用DELETE时,删除了3368个重复项.如果你有更多或更少的重复,性能可能会有所不同.
我用了几次运行每个查询EXPLAIN ANALYZE并取得了最好的结果.一般来说,最好的几乎与第一个或最差的不同.
裸SELECT(没有DELETE)显示类似的结果.
rank()总运行时间:150.411 ms
总运行时间:149.853 ms - 在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;
Run Code Online (Sandbox Code Playgroud)
row_number()总运行时间:148.240 ms
总运行时间:147.711 ms - 在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;
Run Code Online (Sandbox Code Playgroud)
row_number()在子查询中总运行时间:134.753 ms
总运行时间:134.298 ms - 在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;
Run Code Online (Sandbox Code Playgroud)
EXISTS半连接总运行时间:143.777 ms
总运行时间:69.072 ms - 在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)
);
Run Code Online (Sandbox Code Playgroud)
第二轮的差异来自于切换到Hash Semi Join 而不是额外的Sort + Merge Semi Join.
EXISTS 显然可以通过up-tp-date表统计获胜.row_number()子查询中的过时统计信息最快.rank() 是最慢的变种.ANALYZE(更新的统计数据)有助于提高性能并可以提供很多帮 Autovacuum(默认值)应该或多或少地自动处理 - 除了临时表或在表的主要更改之后立即.在这里或这里阅读更多.我用100.000行和63045个重复项重复测试.类似的结果,除了那个EXISTS更慢,甚至之后ANALYZE.
将统计目标提升到1000然后最高为10000(实际超出现金),另一个ANALYZE将所有查询加速约1%,但查询规划器仍然使用Sort + Merge Semi Join for EXISTS.
ALTER TABLE test ALTER COLUMN b SET STATISTICS 10000;
ALTER TABLE test ALTER COLUMN c SET STATISTICS 10000;
ANALYZE test;
Run Code Online (Sandbox Code Playgroud)
只有在我强迫规划人员避免合并加入后,规划人员再次使用Hash Semi Join一半时间:
SET enable_mergejoin = off
Run Code Online (Sandbox Code Playgroud)
从那时起,对查询规划器进行了改进.直接使用Hash Semi加入 PostgreSQL 9.1.7进行重新测试.
| 归档时间: |
|
| 查看次数: |
440 次 |
| 最近记录: |