大型删除查询似乎已冻结


10

我们在具有18亿行的数据库上运行了删除查询。此删除操作将删除12亿行。

事后看来,我们会一次将这个查询分解为100m,但是我们处于一个已运行24小时且日志文件位于2Tb的位置,这似乎是日志文件允许的最大大小。

数据库处于SIMPLE恢复模式。

是否有保存此查询的内容?还是只需要重启SQL Server看看会发生什么?数据库将无法使用吗?我们有什么办法可以尽可能彻底地消除这种情况?


您是从SSMS运行它吗?取消即可。需要一段时间才能取消。只要它已经运行就好。您需要耐心等待。
狗仔队

1
@Graeme根据我们对十亿条记录数据库的经验(我们正在运行其中的几个数据库),有时更快地从受害者表中保存剩余记录,将其截断,删除,将保存的记录重命名为原始名称,然后还原索引(如果有) 。
安东·克鲁格洛夫

1
一旦清除了此spid,我建议批量小于100m,通常是100k至1m。另外,如果可能,请使用主键作为WHERE子句来选择要删除的记录。
BradC

在删除大量数据并尝试避免日志问题时,截断是您的朋友。
Jeff.Clark '17

Answers:


14

首先,检查SQL错误日志以查看它是否真的达到了日志的最大大小。如果这样做了,那么查询就没有希望完成的希望,它可能已经处于回滚状态。

即使是这样,我也总是喜欢手动杀死spid(使用sp_who2sp_WhoIsActive查找spid,然后执行a kill 59或其他操作)。除非您执行显式KILL,否则您也无法检查回滚状态,请参见此相关线程

由于这是删除操作,而不是更新或插入操作,因此您可能很幸运,发现它会立即回滚。如果不是这样,回滚可能要花费与之前相同的时间(或更长)。

要查看回滚状态,请使用

kill 59 with statusonly

不幸的是,我发现这经常没有显示出任何有用的东西,仅仅是“ 0%完成”。在这种情况下,您将不得不使用sp_who2并观察IO和CPU,以查看其是否仍在继续工作。

关于重启,这是一个严重的风险。如果spid正在主动回滚(CPU和IO正在更改),则重新启动SQL将仅使数据库完全脱机,直到回滚完全完成(小时和小时)。但是,如果CPU和IO 没有移动,那么实际上可能会立即清除它。无论哪种方式,都是有风险的。

最后一种选择是,如果情况特别糟糕:如果您在删除操作开始之前就进行了备份(并且没有对数据库进行其他更新),那么恢复的最快方法可能就是简单地删除数据库,然后重新启动SQL,并从备份还原。

如果无法删除数据库(或者如果您已经重新启动实例,并且sql错误日志预计将恢复24小时),请关闭SQL服务,从磁盘上删除MDF和LDF文件,启动SQL,然后删除(ghost)数据库,然后从备份还原。

显然,只有在这是用户未与之交互的后端处理数据库时,您才尝试这样做。


3
关于还原选项的好的建议。吓死人了,但还是个好建议。
Max Vernon

2
是的,在这种情况下,我们让DBA重新启动了实例,这迫使我们在两个非常糟糕的选择之间做出决定:停机18-24小时,或者通过回滚到查询开始之前的回滚来丢失数据。该企业选择回滚。
BradC

1
从3月4日起,我们将拥有完整备份,如果重启无法正常进行,我们将在最后手段恢复该备份。幸运的是,这是一个足够静态的数据库,我们只是想精简一下。感谢您的反馈,非常有帮助
Graeme

4
@Graeme-仅供参考,而不是尝试删除12亿行,而是复制表结构,将要保留的行复制到新表中,然后删除旧表。如果您添加一个新问题来询问如何执行此操作,那么我可以向您展示一种非常巧妙的方法,该方法比删除12亿行要快得多。
Max Vernon

我的答案假设数据库处于简单恢复模式。如果它处于“完全”模式,则还必须管理大量的事务日志备份。
BradC

8

不要重新启动SQL Server。这将只会延长您的痛苦,因为将进行恢复,这将回滚或重做所有未完成的事务,包括删除。

终止正在运行删除操作的会话将导致发生回滚,这也需要很长时间才能完成。

您想查看以下查询以查看操作状态:

SELECT des.session_id 
    , des.host_name
    , des.login_name
    , der.command
    , der.estimated_completion_time
    , der.blocking_session_id
    , der.last_wait_type
    , der.percent_complete
    , der.start_time
    , der.status
    , der.wait_resource
    , der.wait_type
    , der.wait_time
FROM sys.dm_exec_sessions des
    INNER JOIN sys.dm_exec_requests der ON des.session_id = der.session_id
WHERE des.session_id <> @@SPID
    AND des.is_user_process = 1
ORDER BY des.session_id;

仅针对以下操作填充该percent_complete列以及依赖于该列的列estimated_completion_time

ALTER INDEX REORGANIZE
AUTO_SHRINK option with ALTER DATABASE
BACKUP DATABASE
DBCC CHECKDB
DBCC CHECKFILEGROUP
DBCC CHECKTABLE
DBCC INDEXDEFRAG
DBCC SHRINKDATABASE
DBCC SHRINKFILE
RECOVERY
RESTORE DATABASE
ROLLBACK
TDE ENCRYPTION

因此,如果您已经取消了delete语句并且正在回滚,或者如果您已经重新启动了SQL Server并且处于恢复状态,则只会看到该列有意义。

如果该blocking_session_id列包含数字,则表明其他会话正在阻止删除操作。如果该会话自启动以来一直在阻止删除操作,则您可以取消该操作而无需任何回滚。


查询很好,但是如果删除被阻止,日志将变得非常庞大的可能性很小。
BradC

4
是。我只是想稍微解释一下输出。未来的读者也可能会看到这一点。实际上,我怀疑我们下次是否会收到OP的消息。他可能很忙。
Max Vernon
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.