%%lockres%%和%%physloc%%
编辑:2011-10-18
if object_id('ta') is not null
drop table ta
if object_id('tb') is not null
drop table tb
go
create table ta(id int, col1 varchar(20))
create table tb(id int, col2 varchar(20))
create unique clustered index c1 on tb(id)
create nonclustered index nc1 on tb(col2)
go
insert into ta values(1, 'a')
insert into ta values(2, 'b')
insert into ta values(3, 'c')
go
insert into tb values(1, 'a')
insert into tb values(2, 'b')
insert into tb values(3, 'c')
Go
一.%%lockres%%
出现在SQL SERVER 2005及以上版本中。
通过观察发现:只有叶节点(聚集索引和非聚集索引)和数据页(堆,无聚集索引)才需要加锁。非叶节点上是不进行加锁的(为什么?)。如何表示键锁(KEY LOCK)所锁定的键呢?你最初的答案当然是键值了,但是索引的列数目不同,而且类型也不同,所以不太适合表示。SQL SERVER使用一种HASH算法,由键值生成一个6字节的字符串,由这6字节表示键锁所锁定的键。
通过实验发现:该算法应该仅仅跟索引键值有关。
我们可以通过%%lockres%%来查看该hash字符串。由于该字符串值和键值有关,所以通过不同索引查询,会使用不同的键值(叶节点中不同),于是同一数据行的%%lockres%%值也不尽相同。
select *, %%lockres%% from tb with (index=c1)
结果:
id col2
----------- -------------------- --------------------------------
1 a (010086470766)
2 b (020068e8b274)
3 c (03000d8f0ecc)
select *, %%lockres%% from tb with (index=nc1)
结果:
id col2
----------- -------------------- --------------------------------
1 a (62007a313325)
2 b (640044e42670)
3 c (660091aafaf5)
注意:当计划为堆扫描(即没有使用索引),%%lockres%%的值为RID,格式为 文件ID:页ID:行ID。
select *, %%lockres%% from ta
结果:
id col1
----------- -------------------- --------------------------------
1 a 1:77:0
2 b 1:77:1
3 c 1:77:2
二.%%physloc%%
出现在SQL SERVER 2008及以上版本中。它指出数据行的物理地址,其格式为Binary(8),其中1~4字节为pageno(页ID),5~6字节为fileno(文件ID),7~8字节为slotno(行ID),和%%lockres%%不同的是,不管有无聚集索引,%%physloc%%都表示为行所在的物理地址,如果想要显示为常见的文件/数据页/行的格式可以使用下面的函数:
1) 可以使用sys.fn_physlocformatter函数将%%physloc%%转换成一个(file:page:slot)格式的字符串。
2) 如果需要将file/page/slot分别放在一列中,可以使用fn_PhysLocCracker函数。
select *, %%physloc%% as phy from ta
结果:
id col1 phy
----------- -------------------- ------------------
1 a 0x5900000001000000
2 b 0x5900000001000100
3 c 0x5900000001000200
select *, %%physloc%% as phy from tb
结果:
id col2 phy
----------- -------------------- ------------------
1 a 0x5D00000001000000
2 b 0x5D00000001000100
3 c 0x5D00000001000200
经过转换后:
select *, %%physloc%% as phy, sys.fn_physlocformatter(%%physloc%%) as phy1
from ta
结果:
id col1 phy phy1
----------- ------------------- - ------------------ ----------
1 a 0x5900000001000000 (1:89:0)
2 b 0x5900000001000100 (1:89:1)
3 c 0x5900000001000200 (1:89:2)
select a.*, %%physloc%% as phy, b.*
from ta a
cross apply fn_PhysLocCracker(%%physloc%%) b
结果:
id col1 phy file_id page_id slot_id
-------- ------------- ------------------ ----------- ----------- -----------
1 a 0x5900000001000000 1 89 0
2 b 0x5900000001000100 1 89 1
3 c 0x5900000001000200 1 89 2
三.参考文献
1. Microsoft Sql server 2008 internals, p264,p626
2. http://www.sqlskills.com/blogs/paul/post/SQL-Server-2008-New-%28undocumented%29-physical-row-locator-function.aspx
3. http://sqlfool.com/2009/09/undocumented-function-in-sql-2008/