【问题标题】:DELETE whole table except for one row删除除一行以外的整个表
【发布时间】:2012-12-31 05:24:42
【问题描述】:

假设我有一个包含 200k+ 行的表的数据库。
该表有一个 id 为 1800 的固定元组。其余的元组序列从 300k+ 开始。
我需要清理这张表,删除所有记录而不删除 id 为 1800 的一个寄存器。我想出了 3 种类型的查询,我可以运行:

DELETE FROM table WHERE id > 1800
DELETE FROM table WHERE id <> 1800
DELETE FROM table WHERE id NOT IN (1800)

我感觉第一个比其他更快,但我不确定,因为所有其他数据的 id 都大于 1800。

其中哪一个更快,为什么?另外,如果有一种更快捷的方法可以删除除无法删除的记录之外的记录,请告诉我。

【问题讨论】:

  • 最快的可能是将您想要的一条记录复制到临时表中,截断该表,然后将一条记录插入回去
  • 除非查询优化器完全是垃圾(这不太可能),否则这三个是一样的。
  • 视情况而定。如果 id 是(主)键(或索引字段),则三个查询将具有相当的性能。否则:任何事情都会发生,这取决于 id 域的索引和基数。
  • 您可能对密切相关的答案herehere 感兴趣。
  • 是否涉及外键?如果是这样,那也会极大地影响性能。无论如何,如果没有外键,复制记录和截断可能会起作用。如果有外键,那么删除所有其他行是要走的路,遗憾的是它很慢。此外,如果有 FK,请确保它们在引用行上有索引。

标签: sql postgresql optimization sql-delete


【解决方案1】:

大多数数据库中最快的方法是:

  1. 将id为1800的记录选择到临时表中
  2. 删除原始表格
  3. 将临时表中的数据复制到全表中

诚然,由于触发器、约束和权限,这可能是不可能的。在许多数据库中,您可以通过修改 (2) 来截断表而不是删除它来做类似的事情。

至于您最初的问题,实际删除行和与之关联的数据的开销将主导查询。你如何进行比较无关紧要。

示例代码

create temp table saved as
    select * from t where id = 1800

truncate table t

insert into t
    select * from saved

我不确定 Postgres 临时表的命名约定,但这是我的想法。

【讨论】:

  • 虽然这很快,但它使用 DDL 语句而不是 DML 语句来实现,如果您必须关注表间依赖关系,这可能是灾难性的。如果您想要更安全的数据一致性,我倾向于在id 上添加一个索引(如果它不存在的话)并执行delete;因为,要运行删除,您需要先选择记录(因此索引加快了部分操作)。但是,如果原始速度是您唯一关心的问题,那么这可能是最快的方法。
  • 截断几乎总是比删除和重新创建表更好。如果有外键等怎么办?截断要简单得多,并且与删除和重新创建表一样快。 (如果不是更快)
【解决方案2】:

只要它们影响相同的记录,它们就会具有相似的性能。

前者使用索引查找而不是更有效的全表扫描的可能性很小,但可以忽略不计。

【讨论】:

  • 感谢您的出色回答。但是我会接受@GordonLinoff 的回答,因为它提供了一种不同的技术来删除记录。
【解决方案3】:

如果您无法将 ID 移动到新表中,您可能需要尝试分组或批量删除。有时,处理包含大量记录的事务不是最快的。包括任何数据库 oracle 和 microsoft 数据库产品都是这种情况。

BEGIN TRANSACTION;
DELETE FROM table WHERE id >= 0 and  id < 20000 and id != 1800;
COMMIT TRANSACTION;
BEGIN TRANSACTION;
DELETE FROM table WHERE id >= 20000 and  id < 40000 and id != 1800;
COMMIT TRANSACTION;
etc
etc

【讨论】:

    【解决方案4】:

    如果您只想保存最后一条记录并删除所有其他记录,您可以使用以下对我有用的查询

    delete from public.table_name
    WHERE lastrun_ts < (
       select MAX(lastrun_ts)
       FROM public.table_name
       ORDER BY MAX(lastrun_ts) DESC
       );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-15
      • 1970-01-01
      • 2010-09-27
      • 2019-08-11
      • 2017-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多