SQLSERVER中的元數據鎖
網上對於元數據鎖的資料真的非常少
元數據鎖一般會出現在DDL語句里
資源 |
說明 |
RID |
用於鎖定堆(heap)中的某一行 |
KEY |
用於鎖定索引上的某一行,或者某個索引鍵 |
PAGE |
鎖定數據庫中的一個8KB頁,例如數據頁或索引頁 |
EXTENT |
一組連續的8頁(區) |
HOBT |
鎖定整個堆或B樹的鎖 |
TABLE |
鎖定包括所有數據和索引的整個表 |
FILE |
數據庫文件 |
APPLICATION |
應用程序專用的資源 |
METADATA |
元數據鎖 |
ALLOCATION_UNIT |
分配單元 |
DATABASE |
整個數據庫 |
1 --session 1 2 USE [pratice] 3 GO 4 CREATE TABLE ABC(ID INT) 5 GO 6 7 -------------------------- 8 BEGIN TRAN 9 DROP TABLE ABC 10 --COMMIT TRAN
在會話二里使用元數據函數讀取ABC這張表的objectid
1 --session 2 2 USE [pratice] 3 GO 4 --------------------------------------- 5 BEGIN TRAN 6 SELECT OBJECT_ID('ABC') 7 --COMMIT TRAN
這時候就會看到元數據鎖,否則就會出問題
我們看一下在session一里面當drop掉表ABC的時候申請了哪些鎖
1 USE [pratice] 2 GO 3 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ 4 GO 5 6 BEGIN TRAN 7 DROP TABLE ABC 8 9 --COMMIT TRAN 10 11 12 SELECT 13 [request_session_id], 14 c.[program_name], 15 DB_NAME(c.[dbid]) AS dbname, 16 [resource_type], 17 [request_status], 18 [request_mode], 19 [resource_description],OBJECT_NAME(p.[object_id]) AS objectname, 20 p.[index_id] 21 FROM sys.[dm_tran_locks] AS a LEFT JOIN sys.[partitions] AS p 22 ON a.[resource_associated_entity_id]=p.[hobt_id] 23 LEFT JOIN sys.[sysprocesses] AS c ON a.[request_session_id]=c.[spid] 24 WHERE c.[dbid]=DB_ID('pratice') AND a.[request_session_id]=@@SPID ----要查詢申請鎖的數據庫 25 ORDER BY [request_session_id],[resource_type]
SQLSERVER會鎖住一些系統表,例如:syshobts、sysallocunits等,以便對這些系統表進行更新
還有看到SQLSERVER在元數據上加了架構鎖
架構鎖:數據庫引擎在表數據定義語言(DDL)操作(例如添加列或刪除表)的過程中使用架構修改(sch-m)鎖
以阻止其他用戶對這個表格的訪問
數據庫引擎在編譯和執行查詢時使用架構穩定(sch-s)鎖(穩定stable),sch-s鎖不會阻止其他事務訪問表格里的數據,但是,
會阻止對表格做修改性的DDL操作和DML操作
這些元數據應該是位於resource數據庫中
resource數據庫:包含SQLSERVER附帶的所有系統對象副本的只讀數據庫,resource數據庫是不能備份的,而且在SSMS里是看不見的
關於resource數據庫:SQL Server 2005的Resource數據庫
Resource 數據庫是只讀數據庫,它包含了 SQL Server 2005 中的所有系統對象。
SQL Server 系統對象(例如 sys.objects)在物理上存在於 Resource 數據庫中,
但在邏輯上,它們出現在每個數據庫的 sys 架構中。Resource 數據庫不包含用戶數據或用戶元數據。
當查詢某些系統表的時候也會加上元數據鎖
1 USE [pratice] 2 GO 3 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ 4 GO 5 6 BEGIN TRAN 7 select object_id from sys.tables where name = 'xxx' 8 9 --COMMIT TRAN 10 11 12 SELECT 13 [request_session_id], 14 c.[program_name], 15 DB_NAME(c.[dbid]) AS dbname, 16 [resource_type], 17 [request_status], 18 [request_mode], 19 [resource_description],OBJECT_NAME(p.[object_id]) AS objectname, 20 p.[index_id] 21 FROM sys.[dm_tran_locks] AS a LEFT JOIN sys.[partitions] AS p 22 ON a.[resource_associated_entity_id]=p.[hobt_id] 23 LEFT JOIN sys.[sysprocesses] AS c ON a.[request_session_id]=c.[spid] 24 WHERE c.[dbid]=DB_ID('pratice') AND a.[request_session_id]=@@SPID ----要查詢申請鎖的數據庫 25 ORDER BY [request_session_id],[resource_type]
令本人不明白的是:在查詢時,有時候也會加上元數據鎖
建表腳本:

1 USE [pratice] 2 GO 3 --建表 4 CREATE TABLE ct1(c1 INT,c2 INT, c3 VARCHAR (2000)); 5 GO 6 --建立聚集索引 7 CREATE CLUSTERED INDEX t1c1 ON ct1(c1); 8 GO 9 10 --建立非聚集索引 11 CREATE INDEX nt1c1 ON ct1(c2); 12 GO 13 14 15 --插入測試數據 16 DECLARE @a INT; 17 SELECT @a = 1; 18 WHILE (@a <= 1000) 19 BEGIN 20 INSERT INTO ct1 VALUES (@a,@a, replicate('a', 2000)) 21 SELECT @a = @a + 1 22 END 23 GO 24 25 26 27 28 --查詢數據 29 SELECT * FROM ct1
查看申請的鎖
1 USE [pratice] 2 GO 3 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ 4 GO 5 6 BEGIN TRAN 7 SELECT * FROM ct1 WHERE c1=50 8 9 --COMMIT TRAN 10 11 12 SELECT 13 [request_session_id], 14 c.[program_name], 15 DB_NAME(c.[dbid]) AS dbname, 16 [resource_type], 17 [request_status], 18 [request_mode], 19 [resource_description],OBJECT_NAME(p.[object_id]) AS objectname, 20 p.[index_id] 21 FROM sys.[dm_tran_locks] AS a LEFT JOIN sys.[partitions] AS p 22 ON a.[resource_associated_entity_id]=p.[hobt_id] 23 LEFT JOIN sys.[sysprocesses] AS c ON a.[request_session_id]=c.[spid] 24 WHERE c.[dbid]=DB_ID('pratice') AND a.[request_session_id]=@@SPID ----要查詢申請鎖的數據庫 25 ORDER BY [request_session_id],[resource_type]
但是在SQLSERVER2012中
無論是
BEGIN TRAN
select object_id from sys.tables with (nolock) where name = 'xxx'
還是
BEGIN TRAN
SELECT * FROM ct1 WHERE c1=50
都看不到元數據鎖了
1 BEGIN TRAN 2 select object_id from sys.tables with (nolock) where name = 'xxx'
1 BEGIN TRAN 2 select object_id from sys.tables with (nolock) where name = 'xxx'
可能SQLSERVER2012隱藏了元數據鎖,覺得就算顯示出元數據鎖對於排查阻塞也沒有多大意義,干脆隱藏算了
但是這里並不是說SQLSERVER2012沒有了元數據鎖
元數據是一種資源,可以鎖定的資源,元數據鎖並不是一種鎖類型!!!
相關文章:
http://social.msdn.microsoft.com/Forums/zh-CN/10c07757-741d-4473-888c-174c9c91f038
http://social.msdn.microsoft.com/Forums/zh-CN/c5c20bed-3fb7-414e-ade5-fb70c532cd84
http://msdn.microsoft.com/zh-cn/library/ms187812(v=sql.105).aspx
如有不對的地方,歡迎大家拍磚o(∩_∩)o
2014-8-9修正
SQLSERVER也有像ORACLE數據字典的概念,實際上無論哪一種數據庫都有數據字典,只是叫法不同,而sqlserver的數據字典叫元數據而不叫數據字典
mysql 的innodb引擎表會把數據字典存放ibdata共享表空間里
SQLSERVER會把數據字典存放在主文件組
ORACLE會把數據字典存放在system表空間
sqlserver里面的syshobts、sysallocunits表都是帶sys開頭的,都是數據字典
數據字典含義:描述數據的數據
記錄了用戶數據庫中的各個表的表名、字段名、索引信息、表記錄數等等相關信息
所以修改表數據的時候也會修改相應的數據字典表,所以sqlserver就要鎖元數據
實際上無論數據字典還是元數據,實際上就是一張張的表,我們叫系統基本,一般我們是不能操作的,數據庫會利用系統視圖來對
這些系統基表進行封裝屏蔽,例如sqlserver里的sys.[syscolumns]視圖,oracle里面的數據字典視圖,例如以x$ 開頭的靜態數據字典視圖和
v$開頭的動態數據字典視圖(v$database)
文章中的錯誤:這些元數據位於resource數據庫中
這些元數據是各自存放在用戶庫里的,在創建數據庫的時候先從resource數據庫里把這些系統視圖和系統基表結構從resource數據庫里拷貝過來
再從model數據庫里拷貝一些存儲過程、函數和數據庫參數,在這里resource數據庫和model數據庫其實就是創建時候充當模版的角色
而這些系統視圖和系統基表都是以為sys開頭的sys 架構
由於有時候修改表數據的時候也會順帶修改這些系統基表,所以大家也會看到sqlserver申請了元數據鎖
當數據庫啟動的時候,你沒有任何操作,然后關閉數據庫,可以通過開啟sqlserver實例和關閉sqlserver實例來測試
你會看到ldf文件里會記錄修改系統基表的操作,即使你什么操作也沒有做