今天我想談下SQL Server里另一個非常有趣的話題:在SQL Server里停用行和頁層級鎖。在SQL Server里,每次你重建一個索引,你可以使用ALLOW_ROW_LOCKS 和ALLOW_PAGE_LOCKS選項來指定,SQLServer在用讀寫訪問你的數據時,應該獲得行和頁鎖。我們從內部看下,當我們停用這些鎖時會發生什么。
停用行層級鎖
讓我們在一個聚集索引上運行一個簡單的REBUILD操作,這里我們停用行層級鎖:
-- Disable row level locks ALTER INDEX idx_ci ON Foo REBUILD WITH (ALLOW_ROW_LOCKS = OFF) GO
如你從鎖層級里知道的,SQL Server從表層級、頁層級和行級別獲取鎖。現在讓我們在一個顯式事務里運行一個SELECT語句,並且我們用HOLDLOCK查詢提示來把持共享鎖直到事務結束。
-- SQL Server acquires in Repeatable Read a Shared Lock on the Page Level, -- because Shared Row Locks are not possible anymore. BEGIN TRANSACTION SELECT * FROM Foo WITH (HOLDLOCK) WHERE ID = 5000 SELECT * FROM sys.dm_tran_locks WHERE request_session_id = @@SPID ROLLBACK GO
在這個事務期間,當你查看鎖管理器時,你可以看到SQL Server只在表層級獲得IS所,在頁層級獲得共享鎖,沒有行級別的鎖!
這些獲得的鎖現在沒有約束,因為通常SQL Server在頁層級獲得IS鎖,在行本身獲得共享鎖。當你通過一個事務修改你的數據,這個概念同樣適用。
-- SQL Server acquires for an UPDATE statement an Exclusive Lock on the Page Level, -- because Exclusive Row Locks are not possible anymore. BEGIN TRANSACTION UPDATE Foo SET Col2 = REPLICATE('y', 100) WHERE ID = 5000 SELECT * FROM sys.dm_tran_locks WHERE request_session_id = @@SPID ROLLBACK GO
在這個情況下,最后你還是在頁層級有排它鎖,而不是IX鎖。
停用頁層級鎖
接下來讓我們停用頁層級鎖:
-- Disable Page level locks ALTER INDEX idx_ci ON Foo REBUILD WITH (ALLOW_PAGE_LOCKS = OFF) GO
首先我想向你展示下索引重組操作取決於頁層級鎖,因此這個重組操作會失敗:
The index “idx_ci” on table “Foo” cannot be reorganized because page level locking is disabled.
現在讓用重新運行我們的SELECT語句,但這次使用HOLDLOCK查詢提示:
-- There is no IS lock on the Page anymore. BEGIN TRANSACTION SELECT * FROM Foo WITH (HOLDLOCK) WHERE ID = 5000 SELECT * FROM sys.dm_tran_locks WHERE request_session_id = @@SPID ROLLBACK GO
當你再次查看鎖管理器,你會看到在頁層級IS鎖消失了。我們只有在表層級IS鎖,在行層級有共享鎖。
讓我們再來修改一條記錄:
-- There is no IX lock on the Page anymore. BEGIN TRANSACTION UPDATE Foo SET Col2 = REPLICATE('y', 100) WHERE ID = 5000 SELECT * FROM sys.dm_tran_locks WHERE request_session_id = @@SPID ROLLBACK GO
和剛才一樣的事情發生了:SQL Server在表層級獲得IX鎖,在行上獲得排它鎖。在頁層級沒有鎖……
停用行和葉層級鎖
現在讓我們更進一步,對於我們的具體索引停用行和頁層級鎖:
-- Disable Row and Page level locks ALTER INDEX idx_ci ON Foo REBUILD WITH (ALLOW_ROW_LOCKS = OFF, ALLOW_PAGE_LOCKS = OFF) GO
現在當你讀取一些數據,SQL Server只在表層級獲得共享鎖,你的整個表是只讀的:
當你修改沒有獲得頁和行鎖的一條記錄時,SQL Server在整個表上獲得了排它鎖——偶滴神:
小結
這篇文章的意義?為什么你應該在SQL Server里停用頁和行層級鎖,真的沒有一個很好的理由。就用SQL Server提供的默認的鎖策略即可,因為不然的話鎖會約束太多,從而傷及你的性能……
感謝關注!
原文鏈接:
https://www.sqlpassion.at/archive/2016/10/31/disabling-row-and-page-level-locks-in-sql-server/