SQL Server 的事務和鎖(二)-Range S-S鎖

來源:互聯網
上載者:User

在這篇隨筆中,我們的主要關注點在 Key-Range Lock。Key-Range Lock有 S-S、S-U、I-N、X-X幾種情況。我們一個一個來說,力求明白。遺憾的是,這裡可能會比較冗長,那麼死結分析只好依次順延了。

Range S-S鎖的擷取規則

MSDN 對 Range 鎖的規則有部分描述,但是言簡意賅,以下我們會將各種情況分解開來,理清MSDN中涉及的或者未涉及的規則,這些規則適用於SQL Server 2000/2005/2008/2008 R2。關於MSDN的描述,請參見:http://technet.microsoft.com/zh-cn/library/ms191272(en-us,SQL.110).aspx。

在描述規則之前需要聲明的是,我們的叢集索引就建立在 WHERE 字句之上,這很重要,否則是不會獲得 Range 鎖的,也就達不到 SERIALIZABLE 的要求了;另外,為了討論簡便,以下的 SQL 全部省略 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 的聲明。

我們假設有以下的表:

CREATE TABLE [dbo].[MyTable]([id] [int] IDENTITY(1,1) NOT NULL,[index_column] [int] NOT NULL,[data] [int] NOT NULL,CONSTRAINT [PK_MyTable] PRIMARY KEY NONCLUSTERED ([id] ASC)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]) ON [PRIMARY]CREATE UNIQUE CLUSTERED INDEX [IX_MyTable] ON [dbo].[MyTable] ([index_column] ASC)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

並假設我們有如下的資料:

INSERT INTO [MyTable] ([index_column],[data]) VALUES (1, 1)INSERT INTO [MyTable] ([index_column],[data]) VALUES (2, 2)INSERT INTO [MyTable] ([index_column],[data]) VALUES (3, 3)INSERT INTO [MyTable] ([index_column],[data]) VALUES (4, 4)INSERT INTO [MyTable] ([index_column],[data]) VALUES (5, 5)INSERT INTO [MyTable] ([index_column],[data]) VALUES (15, 6)INSERT INTO [MyTable] ([index_column],[data]) VALUES (16, 7)INSERT INTO [MyTable] ([index_column],[data]) VALUES (18, 8)INSERT INTO [MyTable] ([index_column],[data]) VALUES (25, 9)INSERT INTO [MyTable] ([index_column],[data]) VALUES (30, 10)

那麼這張表看起來應該是這樣的(我另外還將Index的Hash值以及row所在的資料頁Dump出來了,以便咱們做實驗)。

id index_column data index hash row page
1 1 1 (8194443284a0) 78
2 2 2 (61a06abd401c) 78
3 3 3 (98ec012aa510) 78
4 4 4 (a0c936a3c965) 78
5 5 5 (59855d342c69) 78
6 15 6 (f1de2a205d4a) 78
7 16 7 (f07ed88b2b23) 78
8 18 8 (e9069d930a93) 78
9 25 9 (b81181109ebc) 78
10 30 10 (8034b699f2c9) 78
對於WHERE子句中的條件命中現有記錄的情況

規則一:如果 WHERE 子句使用的是“相等”條件,例如“WHERE [index_column]=6”,並且該索引是唯一索引,則該索引不會獲得Key-Range S-S鎖,僅僅是Key上獲得普通S鎖;

假設我們執行

SELECT [data] FROM [MyTable] WHERE [index_column]=1

那麼我們使用 sp_lock 得到鎖的情況:

可以發現第一個索引上獲得了S鎖,但並不是 Range S-S 鎖。

規則二:如果 WHERE 子句使用的是“範圍”條件,例如“>、<、BETWEEN、IN”等。不論該索引是否唯一,WHERE子句規定都會成為 Range S-S 鎖作用的範圍,除此之外,在索引定序之下,這個作用範圍的“下一個”索引項目也會獲得Range S-S鎖。

我們必須首先解釋一下“下一個”是怎麼一回事,“下一個”索引項目有兩種情況:

第一:如果在索引定序下,作用範圍之外按照資料排布的方向能夠找到一個存在的,或者是“殘存的”索引項目(已經提交刪除,資料庫中再也看不到了,但是還沒有從B樹資料頁中刪除),那麼這個索引項目就是“下一個”索引項目;

第二:如果在索引定序下,作用範圍之外按照資料排布的方向找不到任何殘存的索引項目,那麼無限遠(Resource Hash為0xffffffff)的索引項目就是“下一個”索引項目。

我們結合規則二進行說明,例如我們執行

SELECT [data] FROM [MyTable] WHERE [index_column]>=1 AND [index_column]<=4

那麼 index_column 中的值為 1、2、3、4的索引會獲得 Range S-S 鎖,除此以外,4之後的下一個索引值,也就是5對應的索引會獲得 Range S-S鎖。這和我們的實驗結果剛好一致。

 

我們再來看著一個,例如我們執行:

SELECT [data] FROM [MyTable] WHERE [index_column]>=20 AND [index_column]<=40

那麼 index_column 為 25、30的索引會獲得 Range S-S 鎖,除此以外,30之後的下一個索引值,也就是“無限遠”會獲得 Range S-S 鎖,請看實際Dump的鎖的使用方式:

 

我們最後練一個稍稍複雜點兒情況:

SELECT [data] FROM [MyTable]

WHERE ([index_column]>=2 AND [index_column]<=4) OR ([index_column]>=10 AND [index_column]<=16) OR ([index_column]>=30 AND [index_column]<=40)

這裡想說明的問題是,我們的“範圍”是指一個個的閉合的範圍,要一個個套用規則進行分析,我們現在有3塊兒閉合的範圍,分別是 [2,4]、[10,16]、[30,40]。我們一個個的來,對於[2,4],在這個範圍內2,3,4,5獲得 Range S-S鎖;

對於[10,16]範圍,15,16,18獲得 Range S-S鎖;對於[30,40]範圍,30,無限遠獲得 Range S-S鎖,一共9個。

 

規則一補充:如果 WHERE 子句使用的是“相等”條件,但是該索引不是唯一索引,那麼除了WHERE命中的索引獲得 Range S-S鎖之外,“下一個”索引也會獲得 Range S-S鎖。

我今天仔細的做了關於這個規則的驗證。另外查閱了 SQL Server 2000 - 2008 Internals 的圖書中關於這個問題的記載。在不是唯一索引的情況下,沒有以上這種固定的選擇規則。以上規則只有在一些特定情況下才出現。而其他規則是沒有問題的。

對於WHERE子句中的條件不能命中任何記錄的情況

規則三:如果 WHERE 子句使用的是“相等”條件,不論索引是否為唯一索引,若不能夠命中任何記錄,除該 WHERE 子句規定的那個不存在的記錄作為 Range S-S的一部分之外,該記錄的“下一個”索引值也將會獲得 Range S-S 鎖。

例如,我們執行

SELECT [data] FROM [MyTable] WHERE [index_column]=6

那麼下一條索引記錄為15所對應的索引,因此這個索引將會獲得 Range S-S 鎖。

 

又例如,我們執行

SELECT [data] FROM [MyTable] WHERE [index_column]=31

那麼下一索引記錄應該是“無限遠”對應的索引,則這個索引將會獲得 Range S-S 鎖。

 

規則四:如果WHERE子句中使用“範圍”條件,不論索引是否為唯一索引,若不能夠命中任何記錄,除該 WHERE 子句規定的那個不存在的範圍作為 Range S-S的一部分外,該範圍的“下一個”索引值也將會獲得 Range S-S鎖。

例如,我們執行

SELECT [data] FROM [MyTable] WHERE [index_column]>=6 AND [index_column]<=10

我實在是寫不動了,請各位開動腦筋吧,這裡直接給結果:

 

再來一個例子吧,我們執行

SELECT [data] FROM [MyTable] WHERE [index_column]>30 AND [index_column]<40

結果是:

 

好了,這一篇終於搞定了。下一篇我們到了 Range S-U 以及 Range I-N 這下會死結了,有好戲看了。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.