在PostgreSQL

时间:2017-11-22 08:05:35

标签: postgresql

我有一个包含大约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%的数据大约需要一分钟。因此,大数据需要很长时间。如果我正在做正确的事情,或者有更好的方法可以做到这一点,请建议。

2 个答案:

答案 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倍,尽管在大多数真实场景中其他成本可能会相形见绌。