我正在研究PostgreSQL 8.1 SQL脚本,该脚本需要从表中删除大量行。
假设我需要删除的表是Employees(~260K行)。 它有一个名为id的主键。
我需要从此表中删除的行存储在一个名为EmployeesToDelete(~10K记录)的单独临时表中,其中包含一个名为employee_id的Employees.id的外键引用。
有一种有效的方法吗?
起初,我想到了以下内容:
DELETE
FROM Employees
WHERE id IN
(
SELECT employee_id
FROM EmployeesToDelete
)
但我听说使用“IN”子句和子查询可能效率低下,尤其是对于较大的表。
我查看了PostgreSQL 8.1文档,并提到了 DELETE FROM ... USING但它没有例子所以我不确定如何使用它。
我想知道以下是否有效并且效率更高?
DELETE
FROM Employees
USING Employees e
INNER JOIN
EmployeesToDelete ed
ON e.id = ed.employee_id
非常感谢您的评论。
编辑: 我运行了EXPLAIN ANALYZE,奇怪的是第一个DELETE跑得很快(几秒钟内),而第二个DELETE花了这么长时间(超过20分钟)我最终取消了它。
向临时表添加索引有助于提高性能。
以下是对任何感兴趣的人的第一个DELETE的查询计划:
Hash Join (cost=184.64..7854.69 rows=256482 width=6) (actual time=54.089..660.788 rows=27295 loops=1)
Hash Cond: ("outer".id = "inner".employee_id)
-> Seq Scan on Employees (cost=0.00..3822.82 rows=256482 width=10) (actual time=15.218..351.978 rows=256482 loops=1)
-> Hash (cost=184.14..184.14 rows=200 width=4) (actual time=38.807..38.807 rows=10731 loops=1)
-> HashAggregate (cost=182.14..184.14 rows=200 width=4) (actual time=19.801..28.773 rows=10731 loops=1)
-> Seq Scan on EmployeesToDelete (cost=0.00..155.31 rows=10731 width=4) (actual time=0.005..9.062 rows=10731 loops=1)
Total runtime: 935.316 ms
(7 rows)
此时,除非我能找到更好的写作方式,否则我会坚持使用第一个DELETE。
答案 0 :(得分:10)
不要猜测,测量。尝试各种方法,看看哪个方法最短。另外,使用EXPLAIN来了解PostgreSQL将要做什么,并查看可以优化的位置。极少数PostgreSQL用户能够猜测正确最快的查询...
答案 1 :(得分:7)
我想知道以下是否有效并且效率更高?
DELETE
FROM Employees e
USING EmployeesToDelete ed
WHERE id = ed.employee_id;
这完全取决于您的索引选择性。
PostgreSQL
倾向于为MERGE IN JOIN
谓词使用IN
,这些谓词具有稳定的执行时间。
只要您已有一个有序的结果集,它就不受满足此条件的行数的影响。
有序的结果集需要排序操作或索引。与PostgreSQL
相比,SEQ SCAN
中的完整索引遍历效率非常低。
另一方面,JOIN
谓词如果您的索引具有非常高的选择性,可能会因使用NESTED LOOPS
而受益,而使用HASH JOIN
它是不敏感的。
PostgreSQL
应该通过估算行数来选择正确的行。
由于您对30k
行有260K
行,我希望HASH JOIN
更有效率,您应该尝试在DELETE ... USING
查询上构建计划。< / p>
为了确保,请发布两个查询的执行计划。
答案 2 :(得分:2)
我不确定DELETE FROM ... USING syntax
,但一般来说,子查询在逻辑上应该与INNER JOIN
相同。数据库查询优化器应该能够(这只是猜测)为两者执行相同的查询计划。
答案 3 :(得分:0)
为什么不能首先删除行而不是将它们添加到EmployeesToDelete
表中?
或者,如果您需要撤消,只需向Employees
添加一个“已删除”标记,这样您就可以在一个表中反转删除或永久删除?