Microsoft SQL Server 2008 R2 (SP2) - 10.50.4042.0 (Intel X86) 2015 年 3 月 26 日 21:49:16 版权所有 (c) Microsoft Corporation Enterprise Edition on Windows NT 6.1(Build 7601:Service Pack 1)
采取的步骤是
创建并启动获取跟踪。
CREATE EVENT SESSION DuringUpdate
ON SERVER
ADD EVENT sqlserver.lock_acquired,
ADD EVENT sqlserver.lock_released
ADD TARGET package0.asynchronous_file_target
(SET filename = 'c:\temp\LockRollback\DuringUpdate.xel',
metadatafile = 'c:\temp\LockRollback\DuringUpdate.xem')
WITH(EVENT_RETENTION_MODE = NO_EVENT_LOSS,
MAX_DISPATCH_LATENCY = 1 SECONDS
);
ALTER EVENT SESSION DuringUpdate
ON SERVER
STATE = start;
开始一个事务并更新 5000 行。
begin transaction;
update dbo.Numbers
set Number = Number
where Number between 1 and 5000;
再更新 10000 行。
update dbo.Numbers
set Number = Number
where Number between 5001 and 15000;
停止获取跟踪。
ALTER EVENT SESSION DuringUpdate
ON SERVER
STATE = stop;
sys.dm_tran_locks通过查询(2 - DB, table)验证是否存在锁。
创建并启动发布跟踪。
CREATE EVENT SESSION DuringRollback
ON SERVER
ADD EVENT sqlserver.lock_acquired,
ADD EVENT sqlserver.lock_released
ADD TARGET package0.asynchronous_file_target
(SET filename = 'c:\temp\LockRollback\DuringRollback.xel',
metadatafile = 'c:\temp\LockRollback\DuringRollback.xem')
WITH(EVENT_RETENTION_MODE = NO_EVENT_LOSS,
MAX_DISPATCH_LATENCY = 1 SECONDS
);
ALTER EVENT SESSION DuringRollback
ON SERVER
STATE = start;
回滚事务。
rollback;
停止发布跟踪。
ALTER EVENT SESSION DuringRollback
ON SERVER
STATE = stop;
整理
DROP EVENT SESSION DuringUpdate
ON SERVER;
DROP EVENT SESSION DuringRollback
ON SERVER;
SELECT
COUNT(*) as DuringUpdate
FROM sys.fn_xe_file_target_read_file(
'c:\temp\LockRollback\DuringUpdate*.xel',
'c:\temp\LockRollback\DuringUpdate*.xem', null, null);
SELECT
COUNT(*) as DuringRollback
FROM sys.fn_xe_file_target_read_file(
'c:\temp\LockRollback\DuringRollback*.xel',
'c:\temp\LockRollback\DuringRollback*.xem', null, null);
SQL Server 不会降级锁定。
我使用包含 100,000 行的“ Numbers ”表进行了调查。根据经验,更新 5,000 行会在
sys.dm_tran_locks
. 更新另外 10,000 行导致升级到单个表锁。这是始终可重现的。为了尽量减少涉及的对象,该表是一个没有索引的堆。我使用扩展事件跟踪来捕获
lock_acquired
事件lock_released
。为了便于分析,我在 UPDATE 和 ROLLBACK 阶段使用了单独的跟踪。使用了两个会话(SSMS 窗口)——一个用于 DML 语句,一个用于跟踪 DDL。我无法使用单个会话,因为我想在事务打开时停止和启动跟踪,这是不允许的。整个隔离级别是 READCOMITTED。
结果
select @@VERSION
是采取的步骤是
创建并启动获取跟踪。
开始一个事务并更新 5000 行。
再更新 10000 行。
停止获取跟踪。
sys.dm_tran_locks
通过查询(2 - DB, table)验证是否存在锁。创建并启动发布跟踪。
回滚事务。
停止发布跟踪。
整理
如果发生锁降级,我希望两个跟踪文件完全对称 - 在 UPDATE 和升级期间获取的每个锁在 ROLLBACK 期间都会有相应的释放。我观察到的:
分别是 383,889 行和 166 行。检查回滚文件的事件 XML,只有一个与 RID、PAGE 或 OBJECTS 相关的事件——释放表上的 X 锁。我由此得出结论,锁定在回滚期间没有降级。
这与回滚到命名保存点的文档相呼应: