【发布时间】:2018-05-04 06:25:08
【问题描述】:
我在处理缓慢的删除查询时遇到了问题。我有一个模式,比如“目标”,其中包含在另一个表中都有等效表(相同的列和主键)的表,比如“delta”。我现在想从目标模式中删除 delta 模式中出现的所有行。我已经尝试过使用 DELETE FROM WHERE EXISTS 方法,但这似乎非常慢。这是一个示例查询:
DELETE FROM "target".name2phoneme
WHERE EXISTS(
SELECT 1 FROM delta.name2phoneme d
WHERE name2phoneme.NAME_ID = d.NAME_ID
AND name2phoneme.PHONEME_ID = d.PHONEME_ID
);
这是两个表的布局(除了“delta”模式只有主键而没有外键)
CREATE TABLE name2phoneme
(
name_id uuid NOT NULL,
phoneme_id uuid NOT NULL,
seq_num numeric(3,0),
CONSTRAINT pk_name2phoneme PRIMARY KEY (name_id, phoneme_id),
CONSTRAINT fk_name2phoneme_name_id_2_name FOREIGN KEY (name_id)
REFERENCES name (name_id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
DEFERRABLE INITIALLY DEFERRED,
CONSTRAINT fk_name2phoneme_phoneme_id_2_phoneme FOREIGN KEY (phoneme_id)
REFERENCES phoneme (phoneme_id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
DEFERRABLE INITIALLY DEFERRED
)
“目标”表最初包含略多于 1800 万行,而增量表包含大约 370 万行(将从目标中删除)。
这是上述查询的 EXPLAIN 的输出:
"Delete on name2phoneme (cost=154858.03..1068580.46 rows=6449114 width=12)"
" -> Hash Join (cost=154858.03..1068580.46 rows=6449114 width=12)"
" Hash Cond: ((name2phoneme.name_id = d.name_id) AND (name2phoneme.phoneme_id = d.phoneme_id))"
" -> Seq Scan on name2phoneme (cost=0.00..331148.16 rows=18062616 width=38)"
" -> Hash (cost=69000.01..69000.01 rows=3763601 width=38)"
" -> Seq Scan on name2phoneme d (cost=0.00..69000.01 rows=3763601 width=38)"
我试图解释分析上述查询,但执行时间超过 2 小时,所以我将其杀死。
关于如何优化此操作的任何想法?
【问题讨论】:
-
删除 370 万行有很多开销。我建议用你想要的行创建一个新表,截断现有的表,然后重新插入你想要的行。
-
您可以尝试使用
WHERE (name_id, phoneme_id) IN (SELECT name_id, phoneme_id FROM other_table)并在(name_id, phoneme_id)上添加索引,但考虑到表格的大小,我不希望有任何快速... -
@jcaron 我尝试了
explain DELETE FROM "target".name2phoneme WHERE (name_id, phoneme_id) in (SELECT d.name_id, d.phoneme_id FROM "delta".name2phoneme d);,结果与 WHERE EXISTS 方法的成本相同。 -
@GordonLinoff 创建一个包含我想要的行的新表需要一个 INSERT INTO ... WHERE NOT EXISTS 构造,它只会产生类似的结果(充其量),不是吗?我们每周都会创建增量表,因此增量模式中的行数可以少很多(甚至为 0)。如果只删除几行,效率会不会更低?
标签: sql postgresql sql-delete