在今天的文章里,我想談下在線索引重建操作(Online Index Rebuild Operations),它們在SQL Server 2014里有怎樣的提升。我們都知道,自SQL Server 2005開始引入了在線索引重建操作。但這些在線操作并非真正的在線操作,因為在操作開始時,SQL Server需要獲得共享表鎖(Shared Table Lock (S)),在操作結束時需要在對應表上獲得架構修改鎖(Schema Modification Lock (Sch-M))。因此這些操作是真正的在線操作,只是營銷技巧(marketing trick)。但是,親,“在線”肯定比“部分在線”好聽多了。
盡管如此,SQL Server 2014還是在在線索引重建的開始和結束發生的阻塞做了一些改進。因此,在你執行在線索引重建時,你可以定義所謂的鎖優先級(Lock PRiority)。來看看下面的代碼,你會看到起作用的新語法:
1 ALTER INDEX idx_Col1 ON Foo REBUILD 2 WITH 3 ( 4 ONLINE = ON 5 ( 6 WAIT_AT_LOW_PRIORITY 7 ( 8 MAX_DURATION = 1, 9 ABORT_AFTER_WAIT = SELF10 )11 )12 ) 13 GO
當阻塞情況發生時,你可以用WAIT_AT_LOW_PRIORITY關鍵字定義如何處理。使用第1個屬性MAX_DURATION指定你想要等待的時間——這里是分鐘,不是秒!用ABORT_AFTER_WAIT屬性你指定哪個會話需要被SQL Server回滾。SELF意味著那個ALTER INDEX REBUILD語句會回滾,當你指定BLOCKERS時,阻塞的會話會回滾。當然,當沒有阻塞發生時,在線索引重建操作會立即執行。因此這里你只能配置當阻塞情況發生時要怎么處理。
好了,我們來實操下。我們新建一個數據庫,一個簡單的表和一個聚集索引。
1 -- Creates a new database 2 CREATE DATABASE Test 3 GO 4 5 -- Use the database 6 USE Test 7 GO 8 9 -- Create a simple table10 CREATE TABLE Foo11 (12 Col1 INT IDENTITY(1, 1) NOT NULL,13 Col2 INT NOT NULL,14 Col3 INT NOT NULL15 )16 GO17 18 -- Create a unique Clustered Index on the table19 CREATE UNIQUE CLUSTERED INDEX idx_Col1 ON Foo(Col1)20 GO21 22 -- Insert a few test records23 INSERT INTO Foo VALUES (1, 1), (2, 2), (3, 3)24 GO
為了觸發阻塞,我在不同的會話開始一個新的事務,但不提交:
1 BEGIN TRANSACTION2 3 UPDATE Foo SET Col2 = 24 WHERE Col1 = 1
這意味著我們在需要修改的記錄上獲得排它鎖(Exclusive Lock (X)),在對應的頁上獲得意向排它鎖(Intent-Exclusive Lock (IX)),在表本身獲得意向排它鎖(Intent-Exclusive Lock (IX))。我們剛剛在SQL Server里創建了典型的鎖定層次(locking hierarchy):表=>頁=>記錄。在表級別的意向排它鎖(IX Lock)和在線索引重建操作需要的共享鎖(Shared Lock)是不兼容的——典型的鎖/阻塞情形發生了。當你現在執行在線索引重建操作時,會發生阻塞:
1 ALTER INDEX idx_Col1 ON Foo REBUILD2 WITH3 (4 ONLINE = ON5 )6 GO
當你查看DMVsys.dm_tran_locks時,你會看到那個需要共享鎖(Shared Lock(S))的會話需要等待。這個會話會永遠等待。我剛才就說過:“部分在線”……
1 SELECT * FROM sys.dm_tran_locks
當我們執行帶有鎖優先級(Lock Priority)的在線索引重建時,有趣的事情發生了:
1 -- Perform an Online Index Rebuild 2 ALTER INDEX idx_Col1 ON Foo REBUILD 3 WITH 4 ( 5 ONLINE = ON 6 ( 7 WAIT_AT_LOW_PRIORITY 8 ( 9 MAX_DURATION = 1, 10 ABORT_AFTER_WAIT = SELF11 )12 )13 ) 14 GO
在這個情況下,我們的ALTER INDEX語句會等待1分鐘(MAX_DURATION),然后語句本身取消了(ABORT_AFTER_WAIT)。
如果你在這里指定了BLOCKERS選項,那么阻塞的會話就會回滾。當我們同時(在1分鐘期間)查看DMVsys.dm_tran_locks,我們看到了有趣的東西:
從圖中可以看到,SQL Server這里請求一個LOW_PRIORITY_WAIT的狀態。因此3個請求狀態(GRANT,WAIT,CONVERT)有了第4個選項:LOW_PRIORITY_WAIT。當我們查看DMVsys.dm_os_waiting_tasks時,事情變得有意思(59是執行語句的會話ID):
1 SELECT * FROM sys.dm_os_waiting_tasks WHERE session_id='59'
在線索引重建操作的等待會話報告了一個新的等待類型LCK_M_S_LOW_PRIORITY。這意味著當在線索引重建操作被阻塞時,我們可以從服務器級別(sys.dm_os_wait_stats)的等待統計信息里獲得——不錯!
但是LCK_M_S_LOW_PRIORITY并不是新的等待類型。在SQL Server 2014里,當你查看DMVsys.dm_os_wait_stats時,會看到21個新的等待類型:
1 SELECT * FROM sys.dm_os_wait_stats WHERE wait_type LIKE '%LOW_PRIORITY%'
所有主要的等待類型(LCK_M_*)都有額外的鎖優先級等待類型。這個非常酷,也非常強大,因為你很容易從中可以跟蹤到為什么在線重建索引操作被阻塞。另外,對于分區切換(Partition Switching)也適用同樣的技術(鎖優先級(Lock Priorities)),因為在切換期間,操作也要在2個表(原表,目標表)上獲取架構修改鎖(Schema Modification Lock (Sch-M))。
我希望這篇文章可以讓你理解SQL Server 2014里的鎖優先級(Lock Priorities),還有為什么SQL Server里的“在線”操作實際上只是“部分在線”。
感謝關注!
新聞熱點
疑難解答