SQLSERVER中的元數據鎖

SQLSERVER中的元數據鎖

網上對於元數據鎖的資料真的很是少html

元數據鎖通常會出如今DDL語句裏mysql

下面列出數據庫引擎能夠鎖定的資源

資源 web

說明sql

RID數據庫

用於鎖定堆(heap)中的某一行session

KEY架構

用於鎖定索引上的某一行,或者某個索引鍵oracle

PAGE ide

鎖定數據庫中的一個8KB頁,例如數據頁或索引頁函數

EXTENT

一組連續的8頁(區)

HOBT

鎖定整個堆或B樹的鎖

TABLE 

鎖定包括全部數據和索引的整個表

FILE

數據庫文件

APPLICATION 

應用程序專用的資源

METADATA   

元數據鎖

ALLOCATION_UNIT  

分配單元

DATABASE

整個數據庫

 
鎖住元數據的目的跟其餘的鎖是同樣的,都是保證事務的一致性
 
實驗環境:SQLSERVER2005 ,SQLSERVER2012,若是沒有特別說明的話,SQL語句都是在SQLSERVER2005上運行
 
例如,在會話一里drop掉ABC表
 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 
View Code

 

查看申請的鎖

 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文件裏會記錄修改系統基表的操做,即便你什麼操做也沒有作

相關文章
相關標籤/搜索