如何从KILLED/ROLLBACK状态中抢救SQL Server 2008查询?

tho*_*ulb 5 sql-server stored-procedures locking sql-server-2008

我有一个存储过程,它将从特定查询中出现的数百万行批量插入到SQL数据库中.它有一个参数选择批次; 当省略此参数时,它将收集批处理列表并递归调用自身,以便迭代批处理.在(伪)代码中,它看起来像这样:

CREATE PROCEDURE spProcedure AS BEGIN
    IF @code = 0  BEGIN
        ...
        WHILE @@Fetch_Status=0 BEGIN
            EXEC spProcedure @code
            FETCH NEXT ... INTO @code
        END
    END
    ELSE BEGIN

        -- Disable indexes
        ...

        INSERT INTO table
        SELECT (...)

        -- Enable indexes
        ...
Run Code Online (Sandbox Code Playgroud)

现在,无论出于何种原因,此过程都很慢:它无法获得锁定,其使​​用的索引之一是错误定义或禁用的.在这种情况下,我希望能够终止该过程,截断并重新创建结果表,然后再试一次.但是,当我尝试杀死该过程时,该过程经常渗入KILLED/ROLLBACK状态,似乎没有返回.从谷歌我学会了做sp_lock,找到spid,然后杀了它KILL <spid>.但当我试图杀死它时,它会告诉我

SPID 75:正在进行事务回滚.预计回滚完成率:0%.预计剩余时间:554秒.

我找到了一个论坛消息,暗示在另一个spid开始回滚之前应该杀死另一个spid.但这对我来说也不起作用,加上我不明白,为什么会出现这种情况......是不是因为我递归调用自己的存储过程?(但它应该有相同的spid,对吧?)

在任何情况下,我的过程只是坐在那里,死了,没有响应杀戮,并锁定桌子.这非常令人沮丧,因为我想继续开发我的查询,而不是在假装完成假定的回滚时等待我的服务器停滞不前的时间.

有什么方法可以告诉服务器不要为我的查询存储任何回滚信息?或者不允许任何其他查询干扰回滚,以便它不会花这么长时间?或者如何以更好的方式重写我的查询,或者如何在不重新启动服务器的情况下成功终止进程?

Bra*_*adC 10

一些评论.

首先,关于无法取消正在进行的回滚,gbn是正确的.这就是SQL保持事务完整性的方式,您不希望这种行为发生变化.如果您完全不在乎并且只是想让您的数据库恢复到最后一次备份时的状态,那么请按照他的步骤操作.

但有一点需要注意.有些时候我已经看到spid 没有真正回滚的地方,它只是停滞不前(通常是0%或100%的进度).在这种情况下,最可靠的指标是,spid in activity监视器的CPU/IO计数器没有变化(并且SPID没有被另一个SPID阻止).在这种情况下,您可能必须重新启动SQL服务(不需要执行整个重新引导)以清除spid.

关于重新组织您的查询,以便这些回滚不会削弱您,是的,它可能.只需使用显式交易:

    WHILE @@Fetch_Status=0 BEGIN
        BEGIN TRANS
            EXEC spProcedure @code
        COMMIT TRANS
        FETCH NEXT ... INTO @code
    END
Run Code Online (Sandbox Code Playgroud)

每批后都会提交数据.如果遇到问题并且必须终止spid,它应该只回滚它正在处理的当前批处理.

如果即使是单个批次太多,您也可以重构"spProcedure"以插入较小批量的10k-100k记录,并在每个记录之后进行.


gbn*_*gbn 9

它正在回滚交易.

即使重新启动实例,它也会继续这样做.

如果您有9亿行进入1亿行插入或删除,则需要回滚所有9900万行.您无法更改此行为.任何单个DML语句都是原子的.

如果你想修复它:

  • 停止SQL Server
  • 删除DB文件
  • 启动SQL Server
  • DB处于破碎状态
  • 恢复

YMMV当然:-)