最近的案子中,在测试及正式环境都碰到了几次数据库事务死结(DeadLock)而有事务被牺牲,有一次还碰上了查询事务的死结(内部平行查询死结intra-Query Parallel Deadlock),由于SQL Server发生死结(DeadLock)的原因很多,因为经验不足,自己没碰过的碰过的多,踏出解问题的第一步就是纪录死结资讯。
来笔记几种观察死结问题的工具。
- Trace flag(1222,1204)
- SQL Profiler
- Extended events
我们把内容分成4篇笔记,让也是工程师的老婆轻松动手做。
第一篇先准备好死结的环境。
死结:
常见的是循环类型死结,事务彼此间使用的资源互斥却互锁,这个资源可能是各种数据对象(数据表、分页、数据列),也可能是线程、内存甚至外部资源。
发生的原因是当二个或多个事务各自具有某个资源的锁定,但事务间想尝试锁定对方事务已锁定的资源,而造成永久封锁(Blocking)导入僵局,也就是死结。简单画一个图例:
事务间陷入了僵局
- (1)Transaction 1持有Resource1的锁定(hold),但事务尚未结束,因此准备进行下一个命令(3)。
- (2)Transaction 2持有Resource2的锁定(hold),但事务尚未结束,因此准备进行下一个命令(4)。
- (3)Transaction 1准备锁定Resource2,但Resource2被Transaction 2锁定,因此被暂时封锁而等待(wait)。
- (4)Transaction 2准备锁定Resource1,但Resource1被Transaction 1锁定,因此被暂时封锁而等待(wait)。
- 可以发现Trsnaction 1与2使用的资源有互斥(mutual exclusion),因此陷入了你等我我等你的循环等待(circular waiting)状态,没有一项工作可以继续执行,出现了死结状态。
好在这时候SQL Server会跳出来公正的仲裁,正所谓牺牲小我完成大我,SQL Server会将复原事务成本较低的事务牺牲(victim),避免僵局时间太久而让交通大打结。
Transaction 2 被迫选择牺牲(查询事务与其他更新或写入事务冲突时,查询事务的复原成本也是最低的)
循环死结:
循环死结,简单的互锁
复杂的三角关系,多个事务间的封锁僵局。
建立死结(DeadLock)的环境
为了让之后的笔记顺利完成,今天先准备环境。
1.建立死结测试所需要的数据库
CREATE DATABASE [DeadLockDb]
CONTAINMENT = NONE
ON PRIMARY
( NAME = N'DeadLockDb', FILENAME = N'C:tempdbDeadLockDb.mdf' , SIZE = 5120KB , FILEGROWTH = 1024KB )
LOG ON
( NAME = N'DeadLockDb_log', FILENAME = N'C:tempdbDeadLockDb_log.ldf' , SIZE = 2048KB , FILEGROWTH = 10%)
GO
2.建立死结测试所需要的两个数据表
create table t1
(
c1 int identity,
c2 varchar(30)
)
create table t2
(
c1 int identity,
c3 varchar(30)
)
3.建立死结测试所需要的测试数据
insert t1 VALUES('Stanley')
insert t2 VALUES('Suzie')
执行测试死结的语法
只要让两个事务互斥锁定对象时间长 (15秒)而且存取Table资源的顺序不同。
查询窗口1(先更新t1再更新t2)
BEGIN Tran Tran_one
UPDATE t1
set c2 = 'lock'
WAITFOR DELAY '00:00:15';
UPDATE t2
set c3 = 'lock'
ROLLBACK
查询窗口2(先更新t2再更新t1):必须在15秒内执行
BEGIN Tran Tran_two
UPDATE t2
set c3 = 'lock'
WAITFOR DELAY '00:00:15';
UPDATE t1
set c2 = 'lock'
ROLLBACK
查询窗口1 x 2的执行结果:
查询窗口2出现了以下的错误消息:
消息 1205,层级 13,状态 45,行 15 事务 (处理序识别码 59) 在 锁定 资源上被另一个处理序锁死并已被选择作为死结的牺牲者。请重新执行该事务。
如果单就log观察,我们AP只能收到以上1205还有被牺牲的错误消息,后面我们来笔记几种观察死结的工具。
小结:
解决循环死结的方向:
- 程序Handle 1205 Error发生后,等待几秒钟,自动重新执行。
- 以相同的顺序来存取对象、降低锁定粒度(Table lock -> Key Lock)、使用较低的隔离层级以及降低锁定的时间(性能调校)等。
参考:
technet侦测与结束死结
https://technet.microsoft.com/zh-tw/library/ms178104(v=sql.105).aspx
Deadlocking
https://technet.microsoft.com/en-us/library/ms177433(v=sql.105).aspx
处理死结
https://technet.microsoft.com/zh-tw/library/ms177453(v=sql.105).aspx
将死结数量降至最低
https://technet.microsoft.com/zh-tw/library/ms191242(v=sql.105).aspx
原文:大专栏 [SQL Server][DeakLock]观察死结的工具(一)首部曲