从 PostgreSQL 表中删除大部分行的有效方法

问题描述 投票:0回答:1

我的 Postgres 数据库中有一个表,大约有 400 万行,我需要将其减少到大约 30,000 行,同时由于外键引用而保留原始 ID。删除的条件基于名为 is_X 的列,并且应删除该列为 false 的行。注意:我正在使用 Ruby on Rails。

我正在寻找最有效的方法来实现这一目标,而不会导致过度的性能下降和维护中断。以下是我正在考虑的一些选择:

  1. 复制-删除-复制回 创建临时表,将符合条件的行复制到临时表中,截断原表,然后将行复制回来。目前这似乎最适合我的问题。但我想进一步调查可能出错的地方。由于我的表有几个索引、外键。
  2. 维护任务 使用数据库维护任务或作业逐步删除块中的行,以减少对性能的影响。不过,我担心这可能需要时间。
  3. 直接删除 使用单个 SQL DELETE 语句直接从表中删除行。虽然这可能很简单,但我不确定这种大小的表是否存在潜在的性能问题。

我正在寻求关于哪种方法在执行时间和数据库性能方面最快、最有效的建议。如果还有其他我没有考虑过的替代方法,也请分享。

任何有效完成此任务的见解、最佳实践或代码示例将不胜感激。

由于其效率和潜在缺点的不确定性,我还没有最终确定其中任何一个。

database postgresql database-migration sql-delete postgresql-performance
1个回答
0
投票

选项1

对于给定的基数,通常在列表中总体上最快 - if它实际上是一个选项。您需要

TRUNCATE
表所需的权限。当截断表中的任何行仍然被引用时,提到的 FK 约束会引发异常。

可能删除 FK 约束,然后重新创建:

BEGIN;

ALTER TABLE other_tbl DROP CONSTRAINT IF EXISTS some_name_fkey;
-- more?

CREATE TEMP TABLE tbl_tmp AS
SELECT * FROM tbl WHERE is_x IS NOT FALSE
-- ORDER BY ??  -- cluster while being at it?
;

TRUNCATE tbl;

INSERT INTO tbl SELECT * FROM tbl_tmp;

ALTER TABLE other_tbl
  ADD CONSTRAINT some_name_fkey FOREIGN KEY (col) REFERENCES tbl(col);
-- more?

COMMIT;

如果涉及临时表,请确保

temp_buffers
设置得足够高以在 RAM 中处理它。参见:

选项 4

但是如果您能做到这一点,您也许可以立即创建一个新表,并删除旧表,跳过临时表。注意其他依赖项,例如视图等。

BEGIN;

ALTER TABLE tbl RENAME TO tbl_old;  -- to free up the name

CREATE TABLE tbl AS
SELECT * FROM tbl_old WHERE is_x IS NOT FALSE
-- ORDER BY ???  -- cluster while being at it?
;

-- comments, constraints, indexes etc.?

ALTER TABLE other_tbl
  DROP CONSTRAINT some_name_fkey  -- drop old
, ADD CONSTRAINT some_name_fkey FOREIGN KEY (col) REFERENCES tbl(col);
-- more?

DROP tbl_old;

COMMIT;

选项5

使用 superuser 权限,您甚至可以禁用所有触发器(FK 约束是通过内部生成的约束触发器实现的)。更快,但更危险。与第一个选项不同,当您再次启用触发器时,不会检查引用完整性。所以你最好确切地知道你在做什么,以免弄坏东西。

BEGIN;

ALTER TABLE tbl DISABLE trigger ALL;  -- are you sure?

CREATE TEMP TABLE tbl_tmp AS
SELECT * FROM tbl WHERE is_x IS NOT FALSE
-- ORDER BY ???  -- cluster while being at it?
;

TRUNCATE tbl;

INSERT INTO tbl SELECT * FROM tbl_tmp;

ALTER TABLE tbl ENABLE trigger ALL;

COMMIT;

参见:

选项3

也就是说,对于几百万行,运行

DELETE
可能是最简单、最安全的。跟进
VACUUM ANALYZE tbl

或者,就这一次,如果排它锁仍然可以,压缩表和索引:

VACUUM FULL ANALYZE tbl;
© www.soinside.com 2019 - 2024. All rights reserved.