提高Sql Delete的性能

时间:2009-02-23 10:44:43

标签: sql database sybase query-optimization database-optimization

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

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

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

8 个答案:

答案 0 :(得分:4)

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

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

  2. 对表格进行分区。创建N个表并使用视图将它们合并为一个。将行排序为按删除标准分组的不同表。我们的想法是删除整个表而不是删除单个行。

答案 1 :(得分:3)

我想知道解析一个包含70K项的IN子句是否有问题。您是否尝试过使用连接的临时表?

答案 2 :(得分:3)

考虑分批运行。一次运行1000条记录的循环可能比执行所有操作的一条查询快得多,此外不会长时间将表锁定给其他用户。

如果您有级联删除(以及许多受影响的外键表)或涉及的触发器,您可能需要以更小的批次运行。您需要体验一下,看看哪种情况最适合您的情况。我有桌子,我必须在100个批次中删除,其他50000个工作(幸运的是,因为我删除了100万条记录)。

但是在任何情况下,我都会将我打算删除的键值放入临时表中并从那里删除。

答案 3 :(得分:2)

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

你能创建subselect而不是IN子句吗?这将缩短sql。也许这可以帮助IN子句中的如此大量的值。像这样:

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

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

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

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

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

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

答案 4 :(得分:2)

找出正在消耗性能的内容!

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

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

但请记住:首先找出正在消耗性能的内容。

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

答案 5 :(得分:1)

尝试按照与表相同的顺序对传入的ID进行排序,或者存储索引。然后,您可以在磁盘缓存上获得更多点击。

将要删除的ID放入临时表中,其中Ids的排序方式与主表的顺序相同,可以让数据库在主表上进行简单的扫描。

您可以尝试使用多个连接并通过连接执行工作,以便使用数据库服务器上的所有CPU,但请先考虑将取出哪些锁等。

答案 6 :(得分:1)

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

如果您要执行“从...中删除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

答案 7 :(得分:0)

our_table是否有关于删除级联的参考?