我有一个包含大约900K行的表。我想删除大约90%的行。尝试使用TABLESAMPLE随机选择它们但没有获得太多的性能提升。以下是我尝试过的查询次数
sql> DELETE FROM users WHERE id IN (
SELECT id FROM users ORDER BY random() LIMIT 5000
)
[2017-11-22 11:35:39] 5000 rows affected in 1m 11s 55ms
sql> DELETE FROM users WHERE id IN (
SELECT id FROM users TABLESAMPLE BERNOULLI (5)
)
[2017-11-22 11:55:07] 5845 rows affected in 1m 13s 666ms
sql> DELETE FROM users WHERE id IN (
SELECT id FROM users TABLESAMPLE SYSTEM (5)
)
[2017-11-22 11:57:59] 5486 rows affected in 1m 4s 574ms
仅删除5%的数据大约需要一分钟。因此,大数据需要很长时间。如果我正在做正确的事情,或者有更好的方法可以做到这一点,请建议。
答案 0 :(得分:3)
删除大量行总是很慢。你如何识别他们的方式不会产生太大的影响。
创建一个包含您想要保留的行的新表,而不是删除大数,通常要快得多,例如:
create table users_to_keep
as
select *
from users
tablesample system (10);
然后截断原始表并插入您存储的行:
truncate table users;
insert into users
select *
from users_to_keep;
如果您愿意,可以在一次交易中完成。
答案 1 :(得分:1)
正如a_horse_with_no_name所指出的,随机选择本身是一个相对较小的因素。与删除相关的大部分成本(例如外键检查)都不是你可以避免的。
唯一突出的不必要的开销是id
语句中基于DELETE
的查找;您刚刚在随机选择步骤中访问了该行,现在您可以再次查找该行,可能是通过id
上的索引。
相反,您可以使用行的物理位置执行查找,由隐藏的ctid
column表示:
DELETE FROM users WHERE ctid = ANY(ARRAY(
SELECT ctid FROM users TABLESAMPLE SYSTEM (5)
))
这让我在人工测试中加速了6倍,尽管在大多数真实场景中其他成本可能会相形见绌。