前段時間,我寫了一些SQL Server里鎖升級的基礎知識,還有它是如何影響執行計劃的。今天,我想進一步談下鎖升級:
鎖升級什么時候發生?
通常在SQL Server里如果在SQL語句里你請求的行數超過5000(SELECT,INSERT,UPDATE,DELETE)會發生鎖升級。例如當你再可重復讀隔離級別(Repeatable Read Isolation Level)里,從表你讀超過5000行數據,鎖升級就會被SQL Server觸發。
當你對超過5000行的數據運行UPDATE和DELETE語句,也會觸發鎖升級。作為副作用,最終你有一個共享(S)或排它(X)表鎖。這肯定會傷及你的并發,降低性能和你工作負載的吞吐量。
“阻塞”鎖升級
鎖升級的整個想法聽起來很簡單,但會有大影響和副作用:如果你不能獲得共享或排它表鎖會發生什么,因為其他人在表上獲得了不兼容的鎖?在這個情況下,鎖升級應該阻塞么?希望不是......
因此我們來構建一個簡單的例子,在這里我們嘗試重現這個情況來看下載這個特定情況下,SQL Server如何反應。下列查詢在Person.Person表里聚集索引里的最后一行請求一個X鎖。
-- This transaction locks the last row in the Clustered Index of the -- table Person.Person BEGIN TRANSACTION UPDATE Person.Person SET LastName = '...' WHERE BusinessEntityID = 20777
這也意味著SQL Server在對應的頁和表本身會獲得意向排它鎖(Intent Exclusive Lock (IX))。現在假設你再可重復讀隔離級別運行SELECT語句,并且你請求超過5000行級別鎖。在這個情況下,SQL Server需要觸發鎖升級,升級各個共享鎖到表級別的共享鎖。
但在我們的情況下不能在表級別獲得共享鎖,因為共享鎖已經已經為我們UPDATE語句授予的IX鎖不兼容。這個鎖層級是有道理的,因為其他人已經造門鎖層級里獲得了不兼容的X鎖。因此我們從Person.Person表的聚集索引SELECT前6000行數據。
-- This statement would trigger a Lock Escalation -- Run this in a different session... BEGIN TRANSACTION SELECT TOP(6000) * FROM Person.Person WITH (HOLDLOCK)
幸運的是,這個SELECT語句沒有阻塞!還不錯!在我們的例子里,SQL Server嘗試進行鎖升級,但放棄了,因為在表層級上有一個不兼容的鎖(IX)。如果鎖升級阻塞的話,情況會更加糟糕,因為這會無故降低并行查詢的并發!
小結:
在SQL Server里鎖升級非常重要,因為它們幫助SQL Server節約里在鎖管理器里的哈希表空間。但鎖升級只被SQL Server“嘗試”。如果SQL Server不能進行鎖升級,因為在表層級有不兼容的鎖,什么也不會發生。鎖升級不能占用空間,觸發鎖升級的SQL語句也不會阻塞。
希望這個特定場景可以幫你更好的理解SQL Server里的鎖升級行為。
原文鏈接:
https://www.sqlpassion.at/archive/2016/05/09/lock-escalations-do-they-always-happen/
不含病毒。www.avast.com |
留言列表