我希望在对两列放置唯一约束之前清理表中的一些数据。
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 ????
输出应为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;
..并添加唯一约束。
我正在考虑与自己进行测试的交叉,但不确定从那里开始做什么。
答案 0 :(得分:5)
EXISTS
变体要快得多 - 正如我预期的那样,与what @Tometzky posted相反。
在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);
在第一轮和第二轮测试之间,我跑了:
ANALYZE test;
当我最终应用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;
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;
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;
EXISTS
半连接总运行时间:143.777毫秒 总运行时间: 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)
);
第二轮的差异来自于切换到 Hash Semi Join 而不是额外的排序+合并半连接。
EXISTS
显然赢得了up-tp-date表统计信息。row_number()
最快。rank()
是最慢的变体。ANALYZE
(更新的统计信息)有助于提高性能,可以帮助很多。 Autovacuum(默认值)应该或多或少地自动处理 - 除了临时表或者在对表进行重大更改后立即执行此操作。阅读更多here或here。我用100.000行和63045个重复项重复测试。类似的结果,除了EXISTS
更慢,即使在ANALYZE
之后。
将统计信息目标提升至1000,然后提高到最大值10000(实际工作量过大),另一个ANALYZE
将所有查询加速约1%,但查询规划器仍然使用 Sort + EXISTS
合并半连接。
ALTER TABLE test ALTER COLUMN b SET STATISTICS 10000;
ALTER TABLE test ALTER COLUMN c SET STATISTICS 10000;
ANALYZE test;
只有在我强迫规划人员避免合并加入后,规划人员再次使用 Hash Semi Join 花费一半的时间:
SET enable_mergejoin = off
从那时起,对查询计划程序进行了改进。使用PostgreSQL 9.1.7重新测试时直接 Hash Semi Join 。
答案 1 :(得分:3)
使用window functions应该比this answer快得多:
select a
from (
select a, rank() over (partition by b, c order by a) as rank
from test ) as _
where rank>1;
答案 2 :(得分:2)
select o.a from test o
where exists ( select 'x'
from test i
where i.c = o.c
and i.b = o.b
and i.a < o.a
);
感谢同事!
答案 3 :(得分:0)
我会尝试一下:
delete from
test
where
a not in (
select min(a)
from test
group by b,c)
在我的机器上20到60毫秒之间,它的价值和分析不会影响计划。
Delete on test (cost=237.50..412.50 rows=5000 width=6)
-> Seq Scan on test (cost=237.50..412.50 rows=5000 width=6)
Filter: (NOT (hashed SubPlan 1))
SubPlan 1
-> HashAggregate (cost=225.00..235.00 rows=1000 width=12)
-> Seq Scan on test (cost=0.00..150.00 rows=10000 width=12)