zoukankan      html  css  js  c++  java
  • SQL Server死锁的解决过程

    某现场报一个SQL死锁,于是开启了1222跟踪:

    dbcc traceon(1222,-1)
    

    一段时间之后拷贝ERROR文件查找相关信息,比较有用的摘录出来如下:

    语句一:

    select study_iuid,station_aet,modality,accession_no,patient_fk,item_attrs,start_datetime  
    from worklist w WITH(readpast), mwl_item m  
    where w.TAG_STUDY_INSTANCE_UID=m.study_iuid  
    and isread='1' and (TAG_SPS_STATUS is null or TAG_SPS_STATUS='SCHEDULED' or TAG_SPS_STATUS='Discontinued')  
    and TAG_SPS_START_DATE between @P0 and @P1   
    and  not exists (select 1 from mpps b where b.study_iuid=m.study_iuid)    
    

    语句二:

    INSERT INTO mwl_item (created_time, updated_time, sps_id, start_datetime, station_aet, station_name, modality, perf_physician, perf_phys_fn_sx, perf_phys_gn_sx, perf_phys_i_name, perf_phys_p_name, req_proc_id, accession_no, study_iuid, item_attrs, sps_status, patient_fk) 
    VALUES (@P0, @P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8, @P9, @P10, @P11, @P12, @P13, @P14, @P15, @P16, @P17);  
    

    相关的死锁资源如下:

    resource-list
     pagelock fileid=1 pageid=6996 dbid=8 objectname=Worklist.dbo.mwl_item id=lock19825c100 mode=IX associatedObjectId=72057594039697408
      owner-list
       owner id=process984d048 mode=IX
      waiter-list
       waiter id=process60e9708 mode=S requestType=wait
     pagelock fileid=1 pageid=11086 dbid=8 objectname=Worklist.dbo.mwl_item id=lock1b087b100 mode=S associatedObjectId=72057594039697408
      owner-list
       owner id=process60e9708 mode=S
      waiter-list
       waiter id=process984d048 mode=IX requestType=wait
    

    可以明显的看到是select语句与insert语句产生了死锁,争用的资源分别6996和11086这两个page,使用dbcc page查看这两个页:

    dbcc traceon(3604)
    go
    dbcc page('Worklist',1,6996,3)
    
    dbcc traceon(3604)
    go
    dbcc page('Worklist',1,11086,3)
     
    发现11086是一个BLOB类型的数据页,而6996是一个数据页(或者说主键聚集索引的叶子页)。查看表结构发现item_attrs是image(BLOB)类型。因此目前的锁争用情况如下:

    1.select进程60e9708持有页11086的S锁,同时请求页6996的S锁。

    2.insert进程984d048持有页6996的IX锁,同时请求页11086的IX锁。

    下图为抓到的相关deadlock graph,与上文中的进程ID不同,不过阻塞语句和情况都一样。

    其原理为:

    1.由最初的303进程的insert语句产生数据页4419的IX锁,同时请求BLOB页17741上的IX锁以便插入BLOB数据,但此时数据页17741上已有与IX不兼容的S锁。

    2.而select语句会在BLOB页17741上加S锁,返回请求数据页4419的行数据失败,因为4419页被insert语句加了不兼容的IX锁,因此两个进程形成死锁。

    这个查询语句是查询当天的数据(这意味着查询基本集中在最后几页),而mwl_item表的主键是自增长的ID,因此插入也是会插入到最后一页。这样造成查询与插入频繁在最后一页生成死锁。

    可能的几种优化方式:

    1.优化select语句使其走mwl_item表的非聚集索引,但是由于本例是insert语句,insert会更新表上的所有索引,因此除非将BLOB列加入包含列,否则无法解决,但BLOB列是不能出现在索引中的。

    2.通知开发优化相关代码的执行频度来避免死锁。

    3.升级程序版本,新版本没有mwl_item表。

    4.将with readpast换成with nolock,读不加共享锁,但会有脏读。

    5.修改全局事务隔离级别为read committed snapshot。

  • 相关阅读:
    实例属性 类属性 实例域 类域
    研究数据集
    static 静态域 类域 静态方法 工厂方法 he use of the static keyword to create fields and methods that belong to the class, rather than to an instance of the class 非访问修饰符
    accessor mothod mutator mothod 更改器方法 访问器方法 类的方法可以访问类的任何一个对象的私有域!
    上钻 下钻 切片 转轴 降采样
    识别会话
    Performance Tuning Using Linux Process Management Commands
    Secure Hash Algorithm 3
    grouped differently across partitions
    spark 划分stage Wide vs Narrow Dependencies 窄依赖 宽依赖 解析 作业 job stage 阶段 RDD有向无环图拆分 任务 Task 网络传输和计算开销 任务集 taskset
  • 原文地址:https://www.cnblogs.com/leohahah/p/6889758.html
Copyright © 2011-2022 走看看