求哪位大侠帮忙分析下死锁日志

游北亮
博客专家认证
2013-06-04 07:46:35
通过 DBCC TRACEON (3605,1204,1222,-1)  
抓到了死锁日志,日志附在下面,我不太明白是,先UPDATE再INSERT,怎么会是有了X锁,再请求RangeS-S锁呢?

具体日志如下:
59:50. spid5s Deadlock encountered .... Printing deadlock information
59:50. spid5s Wait-for graph
59:50. spid5s NULL

59:50. spid5s Node:1
59:50. spid5s KEY: 6:72057594065715200 (8500ea663c04) CleanCnt:2 Mode:RangeS-U Flags: 0x1
59:50. spid5s Grant List 2:
59:50. spid5s Owner:0x00000000077E4AC0 Mode: RangeS-U Flg:0x40 Ref:0 Life:00000001 SPID:66 ECID:0 XactLockInfo: 0x00000007D3EEE3F0
59:50. spid5s SPID: 66 ECID: 0 Statement Type: UPDATE Line #: 92
59:50. spid5s Input Buf: RPC Event: Proc [Database Id = 6 Object Id = 1463676262]
59:50. spid5s Requested by:
59:50. spid5s ResType:LockOwner Stype:'OR'Xdes:0x0000000080092570 Mode: RangeS-U SPID:57 BatchID:0 ECID:0 TaskProxy:(0x000000022CE2C538) Value:0x785b500 Cost:(0/480)
59:50. spid5s NULL

59:50. spid5s Node:2
59:50. spid5s KEY: 6:72057594048806912 (6200429172ae) CleanCnt:2 Mode:X Flags: 0x1
59:50. spid5s Grant List 2:
59:50. spid5s Owner:0x0000000006D05CC0 Mode: X Flg:0x40 Ref:0 Life:02000001 SPID:57 ECID:0 XactLockInfo: 0x00000000800925B0
59:50. spid5s SPID: 57 ECID: 0 Statement Type: UPDATE Line #: 57
59:50. spid5s Input Buf: RPC Event: Proc [Database Id = 6 Object Id = 1463676262]
59:50. spid5s Requested by:
59:50. spid5s ResType:LockOwner Stype:'OR'Xdes:0x00000007D3EEE3B0 Mode: RangeS-S SPID:66 BatchID:0 ECID:0 TaskProxy:(0x00000006C426A538) Value:0x6ba2700 Cost:(0/1236)
59:50. spid5s NULL


59:50. spid5s Victim Resource Owner:
59:50. spid5s ResType:LockOwner Stype:'OR'Xdes:0x0000000080092570 Mode: RangeS-U SPID:57 BatchID:0 ECID:0 TaskProxy:(0x000000022CE2C538) Value:0x785b500 Cost:(0/480)
59:50. spid24s deadlock-list
59:50. spid24s deadlock victim=process6463b88


59:50. spid24s process-list

59:50. spid24s process id=process6463b88 taskpriority=0 logused=480 waitresource=KEY: 6:72057594065715200 (8500ea663c04)
waittime=516 ownerId=773364767 transactionname=UpdateAdAndSetCost lasttranstarted=2013-06-04T08:59:49.450
XDES=0x80092570 lockMode=RangeS-U schedulerid=22 kpid=2872 status=suspended spid=57 sbid=0 ecid=0 priority=0
trancount=3 lastbatchstarted=2013-06-04T08:59:49.453 lastbatchcompleted=2013-06-04T08:59:49.450
clientapp=.Net SqlClient Data Provider hostname=FZTEC-240151 hostpid=61828 loginname=jijin91
isolationlevel=read committed (2) xactid=773364767 currentdb=6 lockTimeout=4294967295
clientoption1=671088672 clientoption2=128056
59:50. spid24s executionStack
59:50. spid24s frame procname=jijin.dbo.PR_InsertAdCostDetail line=57 stmtstart=3438 stmtend=4438 sqlhandle=0x0300060066ed3d57bde7b100d2a100000100000000000000
59:50. spid24s UPDATE a
59:50. spid24s SET a.Cost = a.Cost + b.Cost ,
59:50. spid24s UpdateTime = @now
59:50. spid24s FROM AdvertCostDaily a ,
59:50. spid24s @tblCost b
59:50. spid24s WHERE a.AdId = b.AdId
59:50. spid24s AND a.CostDate = @chToday;
59:50. spid24s --插入扣费汇总表,先清除更新数据
59:50. spid24s --DELETE b FROM @tblCost b
59:50. spid24s -- INNER JOIN AdvertCostDaily a with (nolock) ON a.AdID = b.AdId
59:50. spid24s -- AND a.CostDate = @chToday;
59:50. spid24s --插入到每天汇总表
59:50. spid24s inputbuf
59:50. spid24s Proc [Database Id = 6 Object Id = 1463676262]

59:50. spid24s process id=process7382e08 taskpriority=0 logused=1236 waitresource=KEY: 6:72057594048806912 (6200429172ae)
waittime=516 ownerId=773364742 transactionname=UpdateAdAndSetCost lasttranstarted=2013-06-04T08:59:49.440
XDES=0x7d3eee3b0 lockMode=RangeS-S schedulerid=23 kpid=3400 status=suspended spid=66 sbid=0 ecid=0 priority=0
trancount=3 lastbatchstarted=2013-06-04T08:59:49.443 lastbatchcompleted=2013-06-04T08:59:49.440
clientapp=.Net SqlClient Data Provider hostname=FZTEC-240125 hostpid=151812 loginname=jijin91
isolationlevel=read committed (2) xactid=773364742 currentdb=6 lockTimeout=4294967295
clientoption1=671088672 clientoption2=128056
59:50. spid24s executionStack
59:50. spid24s frame procname=jijin.dbo.PR_InsertAdCostDetail line=92 stmtstart=5774 stmtend=6218 sqlhandle=0x0300060066ed3d57bde7b100d2a100000100000000000000
59:50. spid24s UPDATE a
59:50. spid24s SET a.Cost = a.Cost + b.Cost ,
59:50. spid24s UpdateTime = @now
59:50. spid24s FROM AdvertCost a ,
59:50. spid24s @tblCost b
59:50. spid24s WHERE a.AdId = b.AdId
59:50. spid24s --插入总汇总表,先清除更新数据
59:50. spid24s inputbuf
59:50. spid24s Proc [Database Id = 6 Object Id = 1463676262]


59:50. spid24s resource-list
59:50. spid24s keylock hobtid=72057594065715200 dbid=6 objectname=jijin.sys.query_notification_685245496 indexname=cidx id=lock74d3d00 mode=RangeS-U associatedObjectId=72057594065715200
59:50. spid24s owner-list
59:50. spid24s owner id=process7382e08 mode=RangeS-U
59:50. spid24s waiter-list
59:50. spid24s waiter id=process6463b88 mode=RangeS-U requestType=wait
59:50. spid24s keylock hobtid=72057594048806912 dbid=6 objectname=jijin.dbo.AdvertCostDaily indexname=PK_AdCostDaily id=lock7d41d00 mode=X associatedObjectId=72057594048806912
59:50. spid24s owner-list
59:50. spid24s owner id=process6463b88 mode=X
59:50. spid24s waiter-list
59:50. spid24s waiter id=process7382e08 mode=RangeS-S requestType=wait
...全文
196 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
KevinLiu 2013-06-06
  • 打赏
  • 举报
回复
引用 7 楼 SQL_Beginner 的回复:
你的死锁案例确实比一般的复杂一点,你的 isolationlevel=read committed ,但是出现了key-range 锁,这种情况比较少,一般在indexed view或者外键等级联操作中会出现。 owner id=process7382e08 mode=RangeS-U waiter id=process6463b88 mode=RangeS-U requestType=wait owner id=process6463b88 mode=X waiter id=process7382e08 mode=RangeS-S requestType=wait 首先,从上面看出,不是“已经拥有对象的RangeS-U锁,希望请求的也是RangeS-U锁,”也不是“已经拥有了X锁,它希望请求RangeS-S锁,”, 而是拥有X的process6463b88 请求RangeS-U,跟拥有RangeS-U的process7382e08 ,请求RangeS-S。 另外, 上面那个争抢的资源是: jijin.sys.query_notification_685245496 indexname=cidx ,请问query_notification_685245496是什么?一个表?那还有个表上的索引cidx,跟@tblCostDetail或者你上面的那些语句有什么联系?为什么会用到sys.query_notification_685245496 的cidx?
RangeS-S应该是序列化级别才出现,这里是SQL SERVER 自动将read committed转化为序列化隔离级别了。 类似于这篇文章讲到的:http://blogs.msdn.com/b/conor_cunningham_msft/archive/2009/03/13/conor-vs-isolation-level-upgrade-on-update-delete-cascading-ri.aspx
游北亮 2013-06-06
  • 打赏
  • 举报
回复
非常汗,这个“查询通知”,我的代码已经彻底不用了,并且把数据库的Broker关闭了, 居然还一直报死锁错误,而且也还是跟“查询通知”的那个内部表冲突,坑爹啊。 另外,如果代码里只启用“查询通知”,未停止它,那么数据库里就会多出1个存储过程,1个服务,1个队列,永远无法消失,只能手动删除。
  • 打赏
  • 举报
回复
引用 13 楼 SmithLiu328 的回复:
[quote=引用 7 楼 SQL_Beginner 的回复:] 你的死锁案例确实比一般的复杂一点,你的 isolationlevel=read committed ,但是出现了key-range 锁,这种情况比较少,一般在indexed view或者外键等级联操作中会出现。 owner id=process7382e08 mode=RangeS-U waiter id=process6463b88 mode=RangeS-U requestType=wait owner id=process6463b88 mode=X waiter id=process7382e08 mode=RangeS-S requestType=wait 首先,从上面看出,不是“已经拥有对象的RangeS-U锁,希望请求的也是RangeS-U锁,”也不是“已经拥有了X锁,它希望请求RangeS-S锁,”, 而是拥有X的process6463b88 请求RangeS-U,跟拥有RangeS-U的process7382e08 ,请求RangeS-S。 另外, 上面那个争抢的资源是: jijin.sys.query_notification_685245496 indexname=cidx ,请问query_notification_685245496是什么?一个表?那还有个表上的索引cidx,跟@tblCostDetail或者你上面的那些语句有什么联系?为什么会用到sys.query_notification_685245496 的cidx?
RangeS-S应该是序列化级别才出现,这里是SQL SERVER 自动将read committed转化为序列化隔离级别了。 类似于这篇文章讲到的:http://blogs.msdn.com/b/conor_cunningham_msft/archive/2009/03/13/conor-vs-isolation-level-upgrade-on-update-delete-cascading-ri.aspx[/quote] 是啊,这就是我上面说的外键的级联,当然不止这个,要具体情况具体分析了。
游北亮 2013-06-05
  • 打赏
  • 举报
回复
这个query_notification_685245496是一个INTERNAL_TABLE, 估计是注册“查询通知”自动生成的,汗,它居然还有一个索引叫cidx…… 要去好好研究一下,这个“微软的ADO.NET和SQL Server小组协作开发的新成果”, 实在不行,只能考虑暂时不用这个查询通知了
  • 打赏
  • 举报
回复
引用 9 楼 youbl 的回复:
谢谢回复, 我的这个操作里不存在索引视图,也没有任何的外键, 经过你的提醒,我才想起来,我的系统里有一个查询通知代码,用于当定时去通知程序做一些处理, 不过这个query_notification_685245496却没有什么印象,看objects里是一个内部表, 我再确认一下代码 [quote=引用 7 楼 SQL_Beginner 的回复:] 你的死锁案例确实比一般的复杂一点,你的 isolationlevel=read committed ,但是出现了key-range 锁,这种情况比较少,一般在indexed view或者外键等级联操作中会出现。 owner id=process7382e08 mode=RangeS-U waiter id=process6463b88 mode=RangeS-U requestType=wait owner id=process6463b88 mode=X waiter id=process7382e08 mode=RangeS-S requestType=wait 首先,从上面看出,不是“已经拥有对象的RangeS-U锁,希望请求的也是RangeS-U锁,”也不是“已经拥有了X锁,它希望请求RangeS-S锁,”, 而是拥有X的process6463b88 请求RangeS-U,跟拥有RangeS-U的process7382e08 ,请求RangeS-S。 另外, 上面那个争抢的资源是: jijin.sys.query_notification_685245496 indexname=cidx ,请问query_notification_685245496是什么?一个表?那还有个表上的索引cidx,跟@tblCostDetail或者你上面的那些语句有什么联系?为什么会用到sys.query_notification_685245496 的cidx?
[/quote] 好好确认一下,现在问题就是出在那个jijin.sys.query_notification_685245496上的挣用上。
游北亮 2013-06-05
  • 打赏
  • 举报
回复
谢谢回复, 我的这个操作里不存在索引视图,也没有任何的外键, 经过你的提醒,我才想起来,我的系统里有一个查询通知代码,用于当定时去通知程序做一些处理, 不过这个query_notification_685245496却没有什么印象,看objects里是一个内部表, 我再确认一下代码
引用 7 楼 SQL_Beginner 的回复:
你的死锁案例确实比一般的复杂一点,你的 isolationlevel=read committed ,但是出现了key-range 锁,这种情况比较少,一般在indexed view或者外键等级联操作中会出现。 owner id=process7382e08 mode=RangeS-U waiter id=process6463b88 mode=RangeS-U requestType=wait owner id=process6463b88 mode=X waiter id=process7382e08 mode=RangeS-S requestType=wait 首先,从上面看出,不是“已经拥有对象的RangeS-U锁,希望请求的也是RangeS-U锁,”也不是“已经拥有了X锁,它希望请求RangeS-S锁,”, 而是拥有X的process6463b88 请求RangeS-U,跟拥有RangeS-U的process7382e08 ,请求RangeS-S。 另外, 上面那个争抢的资源是: jijin.sys.query_notification_685245496 indexname=cidx ,请问query_notification_685245496是什么?一个表?那还有个表上的索引cidx,跟@tblCostDetail或者你上面的那些语句有什么联系?为什么会用到sys.query_notification_685245496 的cidx?
最爱午夜 2013-06-05
  • 打赏
  • 举报
回复
插入数据时,如果是使用显示事务,将会出现表锁,这个时候插入是没有问题的,更新和删除,查看(如果需要使用with nolock是可以查看)都不能执行,直到事务释放了,这个锁才会释放。
  • 打赏
  • 举报
回复
你的死锁案例确实比一般的复杂一点,你的 isolationlevel=read committed ,但是出现了key-range 锁,这种情况比较少,一般在indexed view或者外键等级联操作中会出现。 owner id=process7382e08 mode=RangeS-U waiter id=process6463b88 mode=RangeS-U requestType=wait owner id=process6463b88 mode=X waiter id=process7382e08 mode=RangeS-S requestType=wait 首先,从上面看出,不是“已经拥有对象的RangeS-U锁,希望请求的也是RangeS-U锁,”也不是“已经拥有了X锁,它希望请求RangeS-S锁,”, 而是拥有X的process6463b88 请求RangeS-U,跟拥有RangeS-U的process7382e08 ,请求RangeS-S。 另外, 上面那个争抢的资源是: jijin.sys.query_notification_685245496 indexname=cidx ,请问query_notification_685245496是什么?一个表?那还有个表上的索引cidx,跟@tblCostDetail或者你上面的那些语句有什么联系?为什么会用到sys.query_notification_685245496 的cidx?
KevinLiu 2013-06-05
  • 打赏
  • 举报
回复
引用 5 楼 youbl 的回复:
[quote=引用 4 楼 SmithLiu328 的回复:]1 没错 2 insert 的数据来源是通过select来的
感谢楼上的帮助,最后一个小白问题, 成功的那个进程,已经拥有对象的RangeS-U锁,希望请求的也是RangeS-U锁,这2个锁都是UPDATE语句请求的吧?如果是,是不是说,UPDATE会请求多个范围锁呢?而不是一个特别大的范围锁? 另外,INSERT语句应该不会请求RangeS-U锁吧? 看了微软的MSDN,感觉讲的比较粗[/quote] 要看的,因为SQL server 会升级锁,比如更新整张表和更新一条记录锁可能不一样。另外隔离级别也会有影响
游北亮 2013-06-05
  • 打赏
  • 举报
回复
引用 4 楼 SmithLiu328 的回复:
1 没错 2 insert 的数据来源是通过select来的
感谢楼上的帮助,最后一个小白问题, 成功的那个进程,已经拥有对象的RangeS-U锁,希望请求的也是RangeS-U锁,这2个锁都是UPDATE语句请求的吧?如果是,是不是说,UPDATE会请求多个范围锁呢?而不是一个特别大的范围锁? 另外,INSERT语句应该不会请求RangeS-U锁吧? 看了微软的MSDN,感觉讲的比较粗
KevinLiu 2013-06-05
  • 打赏
  • 举报
回复
引用 3 楼 youbl 的回复:
想请教的问题有2个: 1、日志里的sql,是死锁发生时,2个进程执行到的位置,那这个时刻,应该是deadlock victim=process6463b88这个已经被牺牲的时候的位置吧?否则列出来的2个sql根本就不是一个表,怎么可能有死锁?我又没有外键 2、process6463b88这个进程,已经拥有了X锁,它希望请求RangeS-S锁, 而这个进程执行的是UPDATE语句,后面紧跟着是INSERT语句,它请求谁的范围共享锁呢? INSERT也会获取RangeS-S锁吗?
1 没错 2 insert 的数据来源是通过select来的
游北亮 2013-06-05
  • 打赏
  • 举报
回复
想请教的问题有2个: 1、日志里的sql,是死锁发生时,2个进程执行到的位置,那这个时刻,应该是deadlock victim=process6463b88这个已经被牺牲的时候的位置吧?否则列出来的2个sql根本就不是一个表,怎么可能有死锁?我又没有外键 2、process6463b88这个进程,已经拥有了X锁,它希望请求RangeS-S锁, 而这个进程执行的是UPDATE语句,后面紧跟着是INSERT语句,它请求谁的范围共享锁呢? INSERT也会获取RangeS-S锁吗?
KevinLiu 2013-06-05
  • 打赏
  • 举报
回复
上面已经很详细的列出资源竞争,按照这个对应到你的语句做优化。
游北亮 2013-06-04
  • 打赏
  • 举报
回复
下面是并发引起死锁的存储过程的源码,我的代码里通过一个SQL事务去执行这个存储过程的

ALTER PROCEDURE [PR_InsertAdCostDetail]
    @tblCostDetail [AdCostDetailType] READONLY
AS 
    BEGIN
        DECLARE @now DATETIME;
        DECLARE @chToday INT;
        SET @now = GETDATE();
        --把时间变成8位年月日的整数形式,用于sql条件
        SET @chToday = DATEPART(yyyy, @now) * 10000 + DATEPART(m, @now) * 100
            + DATEPART(d, @now);

        --汇总
        DECLARE @tblCost TABLE
            (
              AdId INT ,
              Cost DECIMAL(18, 2)
            );
        INSERT  INTO @tblCost
                ( AdId ,
                  Cost
                )
                SELECT  AdId ,
                        SUM([ActualMoney] * [CostNumber])
                FROM    @tblCostDetail
                GROUP BY AdId

        --Begin  Tran
        --更新扣费汇总表
        --更新到每天汇总表
        UPDATE  a
        SET     a.Cost = a.Cost + b.Cost ,
                UpdateTime = @now
        FROM    AdvertCostDaily a ,
                @tblCost b
        WHERE   a.AdId = b.AdId
                AND a.CostDate = @chToday;
        

        --插入扣费汇总表,先清除更新数据
        --DELETE b FROM @tblCost b
        --                INNER JOIN AdvertCostDaily a with (nolock) ON a.AdID = b.AdId 
        --                                      AND a.CostDate = @chToday;
        --插入到每天汇总表
        INSERT  INTO AdvertCostDaily
                ( AdID ,
                  CostDate ,
                  Cost ,
                  CreateTime ,
                  UpdateTime
                )
                SELECT  b.AdId ,
                        @chToday ,
                        b.Cost ,
                        @now ,
                        @now
                FROM    @tblCost b
                LEFT JOIN AdvertCostDaily a with (nolock) ON a.AdID = b.AdId 
                                              AND a.CostDate = @chToday
                WHERE a.AdID IS NULL;
        --Commit Tran
        

        --Begin  Tran
        --更新到总汇总表
        UPDATE  a
        SET     a.Cost = a.Cost + b.Cost ,
                UpdateTime = @now
        FROM    AdvertCost a ,
                @tblCost b
        WHERE   a.AdId = b.AdId



        --插入总汇总表,先清除更新数据
        DELETE b FROM @tblCost b
                        INNER JOIN AdvertCost a with (nolock) ON a.AdID = b.AdId;
         --插入到总汇总表
         INSERT  INTO AdvertCost
                ( AdID ,
                  Cost ,
                  CreateTime ,
                  UpdateTime
                )
                SELECT  b.AdId ,
                        b.Cost ,
                        @now ,
                        @now
                FROM    @tblCost b;
        --Commit Tran
    END

22,209

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧