zoukankan      html  css  js  c++  java
  • 牛人笔记----(死锁案例分析)

     1 --死锁案例分析 P333
      2 
      3 --先开启监视死锁的开关1222,让SQL遇到死锁时,在errorlog里打印出
      4 --死锁的详细内容
      5 
      6 DBCC TRACEON(1222,-1)
      7 
      8 --这里使用范例表dbo.Employee_Demo_Heap
      9 
     10 --这张表在EmployeeID和ManagerID字段上各有一个非聚集索引,但是没有聚集索引
     11 
     12 
     13 --现在用下面脚本来模拟出一个死锁来。在一个连接里,运行下面语句,反复开启
     14 --事务。在这个事务里,先修改一条NationalIDNumber='480951955'的记录,然后
     15 --把他查询出来。完成以后,再提交事务
     16 
     17 USE [AdventureWorks]
     18 GO
     19 SET NOCOUNT ON
     20 GO
     21 WHILE 1=1
     22 BEGIN
     23 BEGIN TRAN
     24 UPDATE [dbo].[Employee_Demo_Heap]
     25 SET [BirthDate] =GETDATE()
     26 WHERE [NationalIDNumber]='480951955'
     27 SELECT * FROM [dbo].[Employee_Demo_Heap]
     28 WHERE [NationalIDNumber]='480951955'
     29 COMMIT TRAN
     30 END
     31 
     32 
     33 --在另一个连接里也运行这些语句,唯一差别是这次修改和查询是另一条
     34 --NationalIDNumber='407505660'的记录
     35 
     36 USE [AdventureWorks]
     37 GO
     38 SET NOCOUNT ON
     39 --当 SET NOCOUNT 为 ON 时,不返回计数(表示受 Transact-SQL 语句影响的行数)。当 SET NOCOUNT 为 OFF 时,返回计数。如果存储过程中包含的一些语句并不返回许多实际的数据,则该设置由于大量减少了网络流量,因此可显著提高性能。
     40 GO
     41 WHILE 1=1
     42 BEGIN
     43 BEGIN TRAN
     44 UPDATE dbo.[Employee_Demo_Heap]
     45 SET [BirthDate]=GETDATE()
     46 WHERE [NationalIDNumber]='407505660'
     47 SELECT * FROM [dbo].[Employee_Demo_Heap]
     48 WHERE [NationalIDNumber]='407505660'
     49 COMMIT TRAN
     50 END
     51 
     52 
     53 --两条语句一起运行,无须多长时间就会有其中一个连接遇到死锁的错误
     54 
     55 --消息1205,级别13,状态45,第4行
     56 --事务(进程ID 54)与另一个进程被死锁在锁资源上,并且已被选作死锁牺牲品
     57 --请重新运行该事务
     58 
     59 DBCC TRACEON(3604)
     60 DBCC PAGE(9,1,6685,3)
     61 
     62 --常见的四种解决死锁的方法
     63 --1、调整索引,以调整执行计划,减少锁的申请数目,从而消除死锁
     64 --如果死锁的双方不会申请对方要申请的锁,那么死锁也不会发生。如果
     65 --数据库设计者能够引导SQL使用seek的执行计划,只读取要返回的数据,
     66 --那么申请的锁数量会大大降低,死锁的几率也会减少
     67 
     68 --上面的情况可以在NationalIDNumber字段上加一个索引,SQL可以更快地
     69 --找到数据,而无须申请这麽多锁。执行计划都变成seek类型
     70 USE [AdventureWorks]
     71 CREATE NONCLUSTERED INDEX NationalIDNumber ON [Employee_Demo_Heap]([NationalIDNumber] ASC)
     72 
     73 --注意:加索引的时候,如果数据库在运行环境,由于某些查询还在查询数据表那么索引不会添加成功
     74 --除非,预先在建立好表结构的时候就加上索引,或者在晚上停机时间加索引
     75 
     76 --这是一种比较好的方法,能够提高语句执行效率,又消除死锁。所以应该尽可能地使用
     77 --但是他也有局限性,对语句和数据库有下面两个要求:
     78 
     79 --(1)死锁双方处理的数据本身没有交叉
     80 --如果双方都要修改或返回同样的数据,那么再优化索引,可能也没有用处
     81 
     82 --(2)DBA要有权力在数据库里调整索引设计
     83 
     84 --有些数据库是跟着应用来的,DBA必须征得应用开发团队的同意,才能修改数据库设计
     85 --调整之前,要考虑到修改可能会带来的负面作用。不要这个死锁消除了,其他地方
     86 --又出现新的死锁和阻塞
     87 
     88 --当这个方法不可用的时候,可以考虑下面三个比较粗鲁的方法
     89 
     90 --2、使用“nolock”参数,让select 语句不要申请S锁,减少锁的申请数目,从而
     91 --消除死锁
     92 --很多死锁发生在S锁上面,我们可以通过在语句里加“nolock”参数的方法,让
     93 --select语句不要去申请S锁,死锁自然也会消失
     94 USE [AdventureWorks]
     95 GO
     96 SET NOCOUNT ON
     97 GO
     98 WHILE 1=1
     99 BEGIN
    100 BEGIN TRAN
    101 UPDATE [dbo].[Employee_Demo_Heap]
    102 SET [BirthDate] =GETDATE()
    103 WHERE [NationalIDNumber]='480951955'
    104 SELECT * FROM [dbo].[Employee_Demo_Heap] WITH (NOLOCK)
    105 WHERE [NationalIDNumber]='480951955'
    106 COMMIT TRAN
    107 END
    108 
    109 --这个方法解决死锁可以说是立竿见影,所以很多用户很喜欢使用他
    110 --但是缺点很明显
    111 --with (nolock)这个参数意味着,select语句将能接收脏读,这是SQL
    112 --支持的最低一级事务隔离级别。用户要能够理解他的副作用,并且能够
    113 --接受,才能使用
    114 --这种方法只能解决S锁参与的死锁问题,如果死锁发生在U锁或X锁上,with (nolock)
    115 --没有帮助
    116 --这个方法要去修改语句本身。如果语句是由应用程序动态生成,而不是写在SQL
    117 --的存储过程里,要应用开发人员才能够修改
    118 DECLARE @a NVARCHAR(4000)
    119 SET @a='SELECT * FROM [dbo].[Employee_Demo_Heap] WITH (NOLOCK)
    120 WHERE [NationalIDNumber]='+'480951955'
    121 EXEC(@a)
    122 
    123 --3、升级锁粒度,将死锁转化为一个阻塞问题
    124 --死锁产生的原因是双方都申请到了一个资源,同时又要申请对方的资源。
    125 --如果一方一个资源都没有申请到,那么发生的就是阻塞,而不是死锁
    126 --从这个角度讲,如果能想办法让一方被另一方阻塞住,什么资源都申请不到
    127 --那死锁就不会发生
    128 
    129 --从上面的例子里,死锁发生在同一个page上的不同rid上。如果语句直接申请Page
    130 --级别的锁,同时就只能有一个人得到锁资源,而另一个人会被阻塞住。因此,
    131 --使用pagelock这个参数,也能解决这里的死锁问题。
    132 
    133 USE [AdventureWorks]
    134 GO
    135 SET NOCOUNT ON
    136 GO
    137 WHILE 1=1
    138 BEGIN
    139 BEGIN TRAN
    140 UPDATE [dbo].[Employee_Demo_Heap] WITH (PAGLOCK)
    141 SET [BirthDate] =GETDATE()
    142 WHERE [NationalIDNumber]='480951955'
    143 SELECT * FROM [dbo].[Employee_Demo_Heap] WITH (PAGLOCK)
    144 WHERE [NationalIDNumber]='480951955'
    145 COMMIT TRAN
    146 END
    147 
    148 --这种方法虽然不会降低事务隔离级别,但是语句更容易被阻塞住,最终
    149 --的并发度难免受到影响。因此实际上也是一种粗鲁的方法。没有第一种
    150 --通过加索引的方法那么精细。如果能用第一种方法,还是使用第一种方法
    151 --比较负责任
    152 
    153 --4、使用快照隔离级别
    154 --由于这个死锁里有S锁参与,这里把事务隔离级别从默认的已提交读
    155 --改成快照,对缓解这个死锁也会有很好帮助。在语句的开头加上
    156 --这句话就行
    157 SET TRANSACTION ISOLATION LEVEL SNAPSHOT
    158 GO
    159 
    160 USE [AdventureWorks]
    161 GO
    162 SET NOCOUNT ON
    163 GO
    164 WHILE 1=1
    165 BEGIN
    166 BEGIN TRAN
    167 UPDATE [dbo].[Employee_Demo_Heap]
    168 SET [BirthDate] =GETDATE()
    169 WHERE [NationalIDNumber]='480951955'
    170 SELECT * FROM [dbo].[Employee_Demo_Heap]
    171 WHERE [NationalIDNumber]='480951955'
    172 COMMIT TRAN
    173 END
    174 
    175 -----------------------------------总结------------------------------------------------------
    176 --分析和解决死锁的时候,思路要开阔一点,从设计着手
  • 相关阅读:
    Android系统在新进程中启动自定义服务过程(startService)的原理分析
    Thread和Service应用场合的区别
    Android数据格式解析对象JSON用法
    数据交换格式XML和JSON对比
    Android Handler的使用
    Android之Handler用法总结
    Handler的另外一种用法(HandlerThread)
    solr原理
    mysql主从:主键冲突问题
    修改mysql数据库存储目录
  • 原文地址:https://www.cnblogs.com/lx823706/p/5458882.html
Copyright © 2011-2022 走看看