我们有一个查询,根据 id 字段(主键)从表中删除一些行。这是一个非常简单的查询:

delete all from OUR_TABLE where ID in (123, 345, ...)

问题是 id 的数量可能很大(例如70k),因此查询时间较长。有什么办法可以优化这个吗?(我们正在使用 sybase - 如果这很重要的话)。

有帮助吗?

解决方案

考虑分批运行此。同时运行1000只记录一个循环可能会比一个查询,做一切,除了不会保持桌面锁定其他用户,只要一气快得多。

如果您有级联删除(和许多受影响的外键的表)或触发参与,您可能需要运行在更小的批次。你必须实验性功能,看看哪些是适合自己情况的最佳数目。我有表,我必须在100批次,其中人50000(在这种情况下,幸运的,因为我是删除百万条记录)合作,删除。

但在任何连我会把我打算删除到一个临时表,并从那里删除我的键值。

其他提示

有两种方法可以执行这样的语句:

  1. 创建一个新表并复制除要删除的行之外的所有表。之后交换桌子(alter table name ...)我建议尝试一下,即使这听起来很愚蠢。有些数据库的复制速度比删除速度快得多。

  2. 对表进行分区。创建 N 个表并使用视图将它们连接成一个。将行排序到按删除条件分组的不同表中。这个想法是删除整个表而不是删除单个行。

我想知道如果解析与它70K项IN子句是一个问题。你有没有试着用一个临时表连接呢?

Sybase 可以处理 IN 子句中的 70K 参数吗?我使用过的所有数据库都对参数数量有一些限制 IN 条款。例如,Oracle 有 1000 左右的限制。

您可以创建子选择而不是 IN 子句吗?这会缩短sql。也许这对 IN 子句中如此大量的值有帮助。像这样的东西:

  DELETE FROM OUR_TABLE WHERE ID IN 
        (SELECT ID FROM somewhere WHERE some_condition)

如果数据库模型允许,可以通过对数据库进行一些干预来加快删除大量记录的速度。以下是一些策略:

  1. 您可以通过删除索引、删除记录并再次重新创建索引来加快速度。这将消除删除记录时重新平衡索引树的情况。

    • 删除表上的所有索引
    • 删除记录
    • 重新创建索引
    • 如果您与此表有很多关系,并且您绝对确定删除命令不会破坏任何完整性约束,请尝试禁用约束。删除会更快,因为数据库不会检查完整性。删除后启用约束。
    • 禁用完整性约束、禁用检查约束
    • 删除记录
    • 启用约束
    • 禁用表上的触发器(如果有的话)并且您的业务规则允许这样做。删除记录,然后启用触发器。

    • 最后,按照其他建议进行操作 - 制作包含不被删除的行的表的副本,然后删除原始文件,重命名副本并重新创建完整性约束(如果有)。

我会尝试 1、2 和 3 的组合。如果这不起作用,则 4。如果一切都很慢,我会寻找更大的盒子 - 更多的内存,更快的磁盘。

找出是什么消耗了性能!

在许多情况下,您可能会使用提供的解决方案之一。但可能还有其他的(基于 Oracle 知识,所以在其他数据库上情况会有所不同。编辑:刚刚看到你提到了 sybase):

  • 该表上有外键吗?确保引用 ID 已编入索引
  • 您在该表上有索引吗?删除之前删除并删除之后重新创建可能会更快。
  • 检查执行计划。是否使用全表扫描可能更快的索引?或者反过来呢?提示可能有帮助
  • 而不是像上面建议的那样选择 new_table ,而是创建表作为选择可能会更快。

但要记住:首先找出是什么消耗了性能。

当您使用 DDL 语句时,请确保您理解并接受它可能对事务和备份产生的后果。

尝试排序您传递到“中”在相同的顺序表或索引ID存储在。然后,您可能会在磁盘缓存更多的点击。

把ID被删除到具有的ID排序以相同的顺序作为主表中的临时表,可以让数据库做一个简单的过扫描主表

您可以尝试使用一个以上的连接,并在吐涎的连接工作,以便使用所有CPU的数据库服务器上,但是想想锁将被取出等第一。

我还认为,临时表可能是最好的解决方案。

如果你是做一个“从删除..其中ID(选择ID ......)”它仍然是大的查询速度慢,但。因此,我建议你删除使用连接 - 很多人不知道这个功能

因此,考虑到本实施例中的表:

    -- set up tables for this example
    if exists (select id from sysobjects where name = 'OurTable' and type = 'U')
        drop table OurTable
    go

    create table OurTable (ID integer primary key not null)
    go
    insert into OurTable (ID) values (1)
    insert into OurTable (ID) values (2)
    insert into OurTable (ID) values (3)
    insert into OurTable (ID) values (4)
    go

我们可以接着写我们删除代码如下:

    create table #IDsToDelete (ID integer not null)
    go
    insert into #IDsToDelete (ID) values (2)
    insert into #IDsToDelete (ID) values (3)
    go
    -- ... etc ...
    -- Now do the delete - notice that we aren't using 'from'
    -- in the usual place for this delete
    delete OurTable from #IDsToDelete
       where OurTable.ID = #IDsToDelete.ID
    go
    drop table #IDsToDelete
    go
    -- This returns only items 1 and 4
    select * from OurTable order by ID
    go

是否our_table对级联删除一个引用?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top