我正在尝试从匹配查询的表中删除一堆行。我的查询的一般形式是:
DELETE FROM mytable WHERE _id IN (SELECT _id FROM mytable WHERE ...);
该_id
列是一个SERIAL PRIMARY KEY
.
如果我自己运行内部SELECT
查询,它会在大约 1 秒内运行并返回大约 100,000 行。但是,当我将DELETE
调用添加到它时,它似乎只是坐下来大口大口地走开。大口大口地走开。我让它运行了大约一分钟左右,然后假设没有取得任何进展就取消了它。
我添加EXPLAIN ANALYZE
到它的前面,看看我是否可以检查什么花了这么长时间,但那个电话也挂了很长时间。
任何人都可以告诉我可能会发生什么,以便可以非常快速地识别我想要删除的行,但需要不确定的时间来删除它们?
更新:完整查询如下。
DELETE FROM cards
WHERE _id IN (
SELECT _id
FROM cards
LEFT JOIN game_results ON game_results.card_id = cards._id
WHERE NOT available
AND game_id IS NULL
)
Run Code Online (Sandbox Code Playgroud)
表格的简化版本是:
CREATE TABLE cards (_id INTEGER PRIMARY KEY, available BOOLEAN);
CREATE TABLE games (_id INTEGER PRIMARY KEY);
CREATE TABLE game_results (game_id INTEGER REFERENCES games, card_id INTEGER REFERENCES cards);
Run Code Online (Sandbox Code Playgroud)
我确信这个查询最终会完成运行,我只是惊讶于检索所有要删除的 ID 需要多长时间。
解决方案:
问题是三重的!
我运行了一个由中止脚本触发的较早(非常慢!)查询。即使脚本已中止,查询仍在运行。因此,尝试删除索引之类的操作被锁定,等待查询完成。使用手动取消该查询pg_cancel_backend
允许我尝试删除索引和外键约束。
外键约束似乎是减缓一切的问题。game_results
引用的表cards
使删除永远持续的事实。有趣的是,我只是删除了在 game_results 中明确未使用的卡片,但当然这并没有阻止外键检查在删除时发生!这让事情变得非常缓慢。我在运行删除之前删除了外键约束,这将事情加速到我认为合适的水平。
无论出于何种原因,已接受答案中的第二个删除查询比第一个运行得快得多。
通过结合这三件事,我能够在几秒钟内完成整个删除,而在我将这三个因素结合在一起之前,我的查询运行到 5-10 分钟(在我取消它们之前!)。
感谢大家的帮助!
假设列不可为空,查询可以简化(没有自连接)使用NOT IN
或NOT EXISTS
:
DELETE FROM cards
WHERE available = FALSE
AND _id NOT IN
( SELECT card_id
FROM game_results
) ;
DELETE FROM cards AS c
WHERE c.available = FALSE
AND NOT EXISTS
( SELECT *
FROM game_results AS gr
WHERE gr.card_id = c._id
) ;
Run Code Online (Sandbox Code Playgroud)
尽管如此,删除 100K 行不能瞬间完成。性能可能会受到缺少(或过多)索引、触发器、级联删除等的影响。
您可以使用EXPLAIN
(only, without ANALYZE
) 来获取DELETE
. 查看EXPLAIN
详情,特别是如果你想尝试ANALYZE
EXPLAIN 或其他选项:
重要提示:请记住,
ANALYZE
使用选项时实际上会执行该语句。尽管EXPLAIN
将丢弃 SELECT 将返回的任何输出,但该语句的其他副作用将照常发生。如果您希望EXPLAIN ANALYZE
在INSERT
,UPDATE
,DELETE
,CREATE TABLE AS
, 或EXECUTE
语句上使用而不让命令影响您的数据,请使用以下方法:Run Code Online (Sandbox Code Playgroud)BEGIN; EXPLAIN ANALYZE ...; ROLLBACK;
检查没有什么阻止了DELETE
:
查看 pg_locks 向您显示授予了哪些锁以及哪些进程正在等待获取锁。开始寻找锁定问题的一个很好的查询:
Run Code Online (Sandbox Code Playgroud)SELECT relation::regclass, * FROM pg_locks WHERE NOT GRANTED;
归档时间: |
|
查看次数: |
12368 次 |
最近记录: |