解决该问题的最简单的方法是从PostgreSQL查询详细时序:EXPLAIN
。为此,您至少需要找到一个可以完成但比预期更长的查询。假设这条线看起来像
delete from mydata where id='897b4dde-6a0d-4159-91e6-88e84519e6b6';
无需真正运行该命令,您可以执行
begin;
explain (analyze,buffers,timing) delete from mydata where id='897b4dde-6a0d-4159-91e6-88e84519e6b6';
rollback;
最后的回滚允许在不真正修改数据库的情况下运行此操作,但是您仍然可以详细了解花费了多少时间。运行该命令之后,您可能会在输出中发现某些触发器会导致巨大的延迟:
...
Trigger for constraint XYZ123: time=12311.292 calls=1
...
的单位time
是毫秒(毫秒),因此检查此约束大约需要12.3秒。您需要INDEX
在必填列上添加新的内容,以便可以有效地计算此触发器。对于外键引用,必须索引引用另一个表的列(即,源列,而不是目标列)。PostgreSQL不会自动为您创建此类索引,它DELETE
是您真正真正需要该索引的唯一常见查询。结果,您可能已经积累了多年的数据,直到遇到DELETE
由于缺少索引而导致速度太慢的情况。
一旦具有固定的约束性能(或花费过多时间的其他事情),请在begin
/ rollback
块中重复该命令,以便可以将新的执行时间与上一个执行的时间进行比较。继续,直到您对单行删除响应时间满意为止(只需添加不同的索引,我就可以使查询从25.6秒缩短到15 ms)。然后,您可以继续进行完整删除,而不会受到任何攻击。
(请注意,这EXPLAIN
需要一个可以成功完成的查询。我曾经遇到一个问题,PostgreSQL花了很长时间才弄清楚一个删除将违反外键约束,在这种情况下EXPLAIN
无法使用,因为它不会发出失败的时间在这种情况下,我不知道调试性能问题的任何简便方法。)