【问题标题】:Why does ON DELETE CASCADE sometimes take long on Postgres 9?为什么在 Postgres 9 上 ON DELETE CASCADE 有时需要很长时间?
【发布时间】:2012-11-30 02:25:03
【问题描述】:

我在表之间有一些关系,这些关系都与一个“所有者”表相关。所以只是为了这个例子:

  • 具有 PK id 的表所有者
  • 带有 PK id 和 FK owner_id 的表父级引用 Owner.id,上面有索引,以及 ON DELETE CASCADE
  • 具有 PK id 和 FK parent_id 的 Table Child 引用 Parent.id,上面有一个索引,以及 ON DELETE CASCADE

Child 表很大(约 5000 万行),Parent 表有几千行,而 Owner 表非常小(约 10 行)。

还有一些与 Owner 和 Parent 相关的其他表,但它们相对较小(几千个)并且还具有外键索引和 ON CASCADE DELETE

有时,当我删除通过所有删除级联的所有者行(大约 1200 万个子行和 1000 个父行)时,工作速度非常快(几秒钟),但有时需要将近一个小时。

我如何找出造成这种情况的原因?我在delete from child where parent_id in (select id from parent where owner_id = 1) 上做了explain,其中 1 是所有者行之一的 id(我尝试了各种 id 只是为了确保),据说它正在使用 Bitmap Heap Scan -> Bitmap Index Scan and Index Scan .但是,我不确定我是否在模仿ON DELETE CASCADE 触发器时的实际操作。我怎样才能弄清楚是什么导致了这些巨大的延误?是不是有时 Postgres 更喜欢进行顺序扫描(由于行数)?

插入相同的行只需要 8 分钟(包括应用程序逻辑和几千个事务提交),所以我不明白为什么直接删除需要这么长时间。

我正在使用 Postgres 9.1.6

【问题讨论】:

  • 请尝试解释分析
  • 尝试解释从 child where parent_id in (select_id from parent where owner_id = 1) 中删除分析并获得相同的位图堆扫描 -> 位图索引等。得到这些成本:(成本 = 150.01.. 562757.84 rows=6560827 width=12) (实际时间=39.792..39.792 rows=0 loops=1)
  • 有可怕的错误统计 - 所以位图索引扫描不是最佳的 - 请尝试禁用 bitmap_scan -- "set enable_bitmapscan to off"
  • 我执行了set enable_bitmapscan to off 并再次执行了explain analyse,现在它只使用了index scan。但是我再次尝试删除它仍然需要很长时间:(
  • @Matthieu 不幸的是没有。现在已经有几年了,但如果我记得清楚的话,当我需要删除如此大量由外键链接的子项时,我删除了索引并在之后重建了它们。

标签: postgresql postgresql-9.1


【解决方案1】:

你说有时会从几秒到几小时。有相当多的行要删除。您可能要处理从数据缓存到行锁的各种因素。不幸的是,如果这些是暂时的情况,那么在没有发生时可能很难追踪它们。

您最初应该查看的几件事是您是否可以找到任何模式。当它发生时看看SELECT * FROM pg_locks。当问题发生时,您还应该SELECT * FROM pg_stat_activity 查看可能持有锁的位置。

【讨论】:

  • 没有锁,没有其他人在访问数据库。 (事实上​​,我有时只是删除数据库来清理数据,因为删除它需要很长时间,而且它允许我)。是的,有大量的行,但插入它们需要 8 分钟,所以删除它们需要几个小时是没有意义的。我最近从默认值中增加了 shared_bufferseffective_cache_size,这似乎有一些效果,将其缩短到大约 20 分钟......更好但不确定它是否是最佳的。
猜你喜欢
  • 2012-01-14
  • 2011-04-22
  • 1970-01-01
  • 1970-01-01
  • 2017-06-20
  • 2021-08-16
  • 2010-11-28
  • 2021-11-22
  • 2016-02-15
相关资源
最近更新 更多