如何加快删除没有行的文档

Posted

技术标签:

【中文标题】如何加快删除没有行的文档【英文标题】:How to speed up deleting documents without rows 【发布时间】:2015-09-26 07:39:33 【问题描述】:

文档标题在 omdok 表中:

create table omdok ( dokumnr serial primary key, ... );

文档行在 omrid 表中

CREATE TABLE omrid
(
  id serial NOT NULL,
  reanr serial NOT NULL,
  dokumnr integer NOT NULL,
  CONSTRAINT omrid_pkey PRIMARY KEY (id),
  CONSTRAINT omrid_dokumnr_fkey FOREIGN KEY (dokumnr)
      REFERENCES omdok (dokumnr) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY IMMEDIATE,
  ....
);

omdok 中没有 omrid 子行的记录需要删除

我试过了

delete from omdok where dokumnr not in      (select dokumnr from omrid)

查询它目前正在运行 15 小时并且仍在运行。 postgres.exe 一直在使用 50% 的 CPU(这是 2 核 CPU)。

explain delete from omdok where dokumnr not in      (select dokumnr from omrid)

返回:

"Delete  (cost=0.00..21971079433.34 rows=220815 width=6)"
"  ->  Seq Scan on omdok  (cost=0.00..21971079433.34 rows=220815 width=6)"
"        Filter: (NOT (SubPlan 1))"
"        SubPlan 1"
"          ->  Materialize  (cost=0.00..94756.92 rows=1897261 width=4)"
"                ->  Seq Scan on omrid  (cost=0.00..77858.61 rows=1897261 width=4)"
如何快速删除没有子行的父母? 此命令会完成还是 postgres 挂起? 目前运行 15 小时。需要多少小时才能完成? 如何加快查询速度?

使用

PostgreSQL 9.0.1, compiled by Visual C++ build 1500, 64-bit

Windows 2003 x64 server with 4 GB RAM.

【问题讨论】:

【参考方案1】:

您没有以任何方式限定您的 DELETE 查询,因此将 220,815 个文档与 1,897,261 个文档行进行比较。这需要时间。

最简单的优化是在文档行上使用DISTINCT 子句,这应该会使omrid 中的行减少8 倍左右:

DELETE FROM omdok WHERE dokumnr NOT IN (SELECT DISTINCT dokumnr FROM omrid);

一个可能更快的解决方案是首先识别没有行的文档,然后删除这些行:

WITH docs0rows AS (
  SELECT dokumnr
  FROM omdok d
  LEFT JOIN (SELECT DISTINCT dokumnr FROM omrid) dr ON dr.dokumnr = d.dokumnr
  WHERE dr.dokumnr IS NULL
)
DELETE FROM omdok d
USING docs0rows zero
WHERE d.dokumnr = zero.dokumnr;

免责声明:在运行此命令之前对其进行测试以查看将删除哪些行。

【讨论】:

它会导致错误列引用“dokumnr”不明确。可能 omdok.dokumnr 应该在 delete where 子句中使用。 using 子句在 9.0 中有效还是应该从 ? DELETE 语句中,您使用USING 而不是FROM 来指定额外的表来构建过滤条件子句。适用于所有版本。答案已更正。 为什么在 delete 中使用别名 d 和 zero?删除它们并改用表名是否安全?【参考方案2】:

另一种选择是在omrid(dokumnr) 上简单地创建一个索引:

create index idx_omrid_dokumnr on omrid(dokumnr);

这应该会加快原始查询中not in 的处理速度。

【讨论】:

psql-genral 邮件列表建议替换为delete from omdok where not exists(select 1 from omrid where omdok.dokumnr = omrid.dokumnr); @Andrus。 . .我也更喜欢not exists,但我认为该索引适用于任何一种表述。

以上是关于如何加快删除没有行的文档的主要内容,如果未能解决你的问题,请参考以下文章

如何加快 CockroachDB 中的插入性能

如何加快一系列文档中键的存在总和? - 熊猫,nltk

从数据框中删除行的命令[重复]

如何确定 Qt 文档行的渲染高度

有没有办法加快对 t1 和 t1 中百万行的查询?

如何加快rbind?