T-SQL优化许多记录的DELETE

got*_*tqn 11 sql t-sql sql-server sql-delete

我有一张表可以增长到数百万条记录(例如5000万条记录).每20分钟删除超过20分钟的记录.

问题是,如果表有这么多记录,这样的删除可能会花费很多时间,我想让它更快.

我不能做"截断表",因为我只想删除超过20分钟的记录.我想在执行"删除"并过滤需要删除的信息时,服务器正在创建日志文件或其他东西,这需要花费很多时间?

我对吗?有没有办法停止任何标志或选项来优化删除,然后打开已停止的选项?

Hea*_*ore 14

为了扩展批量删除建议,我建议你更经常地这样做(也许每20秒) - 批量删除很容易:

WHILE 1 = 1 
    BEGIN 
        DELETE TOP ( 4000 )
        FROM    YOURTABLE
        WHERE   YourIndexedDateColumn < DATEADD(MINUTE, -20, GETDATE()) 
        IF @@ROWCOUNT = 0 
            BREAK    
    END
Run Code Online (Sandbox Code Playgroud)

在等待锁释放时,您的插入可能会稍微滞后,但它们应该插入而不是错误.

但是对于你的桌子,我希望在一个非常快速的raid 10阵列/甚至是分区上看到这么多流量的表 - 你的磁盘到底了吗?您的事务是否在不同磁盘上记录到数据文件中?- 他们应该是

编辑1 - 回复您的评论

将数据库置于SIMPLE恢复中:

ALTER DATABASE Database Name SET RECOVERY='SIMPLE'
Run Code Online (Sandbox Code Playgroud)

这基本上会关闭给定数据库上的事务日志记录.在数据丢失的情况下,您需要在上次完全备份后丢失所有数据.如果你没关系,那么在运行大型事务时应该节省大量时间.(注意,当事务正在运行时,日志记录仍然在SIMPLE中进行 - 以启用事务的回滚).

如果您的数据库中有表格无法承受松散的数据,则需要将数据库保留为完全恢复模式(即任何事务都会被记录(并希望通过服务器维护计划刷新到*.trn文件).虽然在我的问题中说明,没有什么可以阻止你有两个数据库,1个在FULL中,1个在SIMPLE中.FULL数据库是fore table,你不能放松任何数据(即你可以应用事务日志来恢复数据到特定时间)SIMPLE数据库将用于这些大型高流量表,您可以在发生故障时允许数据丢失.

假设您每晚创建完整的(*.bak)文件并每半小时左右将日志文件刷新到*.trn文件,所有这些都是相关的.

关于您的索引问题,如果您检查执行计划并查看任何"表扫描",则必须对您的日期列编制索引,这将指示缺少索引.

您假设的日期列是DATETIME,其约束是将DEFAULT设置为getdate()吗?

您可能会发现通过用BIGINT YYYYMMDDHHMMSS替换它来获得更好的性能,然后将CLUSTERED索引应用于该列 - 请注意,每个表只能有1个聚簇索引,因此如果该表已经有一个,则需要使用非聚集索引.(如果您不知道,聚集索引基本上告诉SQL以该顺序存储信息,这意味着当您删除行> 20分钟时,SQL可以按字面顺序删除内容而不是从一个页面跳到另一个页面.


Car*_*ppa 10

日志问题可能是由于在trasaction中删除了记录的数量,更糟糕的是引擎可能正在请求每个记录锁定(或者通过页面并不是那么糟糕)

这里最重要的一点是你如何确定要删除的记录,我假设你使用了一个日期时间字段,如果是这样,请确保你在列上有一个索引,否则它是对表格的顺序扫描,这将严重影响你的过程.

根据用户的并发性和删除时间,您可以做两件事

  1. 如果您可以保证删除时没有人要读取或写入,您可以将表锁定在独占模式并删除(这只需要从引擎锁定一个)并释放锁定
  2. 您可以使用批量删除,您可以创建一个带有游标的脚本,该游标提供您要删除的行,然后开始transtaction并提交每个X记录(理想情况下为5000),这样您就可以保持事务的短路并且不会占用那么多锁

看一下删除过程的查询计划,看看它显示了什么,对大表的顺序扫描从来没有好过.