zoukankan      html  css  js  c++  java
  • 数据库死锁分析和说明:select和update死锁场景举例

    背景说明:

    表结构和索引情况:

     

     

    select操作语句和执行计划如下: select  [DL_ID] ,[Name],Age from TT_DeadLock where Name ='xxxxxxxx'

     

    update操作语句和执行计划如下::update TT_DeadLock set Name= 'jack1',[LastModifier]='chenzk' ,[LastModifyTime]=GETDATE() where DL_ID='0001FC1D-6DA9-4EDE-91BD-571158477BB3';

     

       

    验证执行:

    背景交代完毕,现在我们分别循环的执行以上两个操作,很快就会发生死锁,如下图:

     

    额外说明:左侧窗口是模拟高频执行update操作,右侧窗口模拟高频执行select操作。其中存储过程定义如下:

    ALTER PROC [dbo].[GetAgeByNameProc] @NameStr varchar(100) AS

    select  [DL_ID] ,[Name],Age from TT_DeadLock where Name =@NameStr

      

    分析原因:

    既然确实发生了死锁,那说明存在两个操作互相等待对方持有的锁。

      我们先分析Select操作:根据索引和执行计划可以看到,先执行非聚集索引seek,由于select的Age列没有在idx_Name中覆盖,因此要执行key lookup获取Age列。这两步操作隐含了2把锁:idx_Name的S锁和key looup操作中聚集索引的S锁。

      然后在看Update操作:由于是update操作因此显然会对主键聚集索引增加X锁,但是这里由于更新的列Name恰好也包含在索引idx_Name中,因此就需要更新idx_Name索引的内容,也就是说也要对idx_Name增加一把X锁。

      说清楚了以上两个操作的内部细节,我们将其格式化看看:

     
    Update操作
    Select操作
    备注
    第一步
    更新主键聚集索引--加X锁
    seek普通索引idx_Name--S锁
     
    第二步
    更新普通索引idx_Name--加X锁
    key lookup操作(主键索引seek)--S锁
     
    第三步
    执行结束commit
    执行结束commit
     
      根据以上表格的情况,可以清楚的看到:当并发执行双方操作同时进入第二步,就出现了互相等待的情况:Update操作等Select释放idx_Name的S锁、Select操作等Update释放主键聚集索引的X锁。

    解决办法:

    思路就是:打断其中任何一个环节,避免互相等待。

    方案一:优化idx_Name索引,实现Age列覆盖

    方案二:Update操作和Select操作的执行时增加程序锁,将并发强制改为串行执行。

    方案三:Select操作增加with(nolock)【对select数据要求不严格时可用,因为会产生脏数据的问题】

  • 相关阅读:
    神奇的C语言
    实现代码编辑器
    实现了一个简单的key-value存储系统
    一些官网说明
    苹果用户转入mate30,被恶心到了
    吐嘈一下乱用注入
    谈一下OOP的乱用现象
    mongo3.x ssl版安装文件
    再谈LRU双链表内存管理
    cocos在win平台exe无法使用 UserDefault 解决方法
  • 原文地址:https://www.cnblogs.com/chen943354/p/13571201.html
Copyright © 2011-2022 走看看