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

How to speed up deleting documents without rows

文件 headers 在 omdok table:

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

文档行在 omrid 中 table

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 中没有 child 行需要删除

我试过了

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)

returns:

"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)"

使用

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

Windows 2003 x64 server with 4 GB RAM.

您没有以任何方式限定您的 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;

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

另一种方法是简单地在 omrid(dokumnr):

上创建一个索引
create index idx_omrid_dokumnr on omrid(dokumnr);

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