前段時間,我寫了一些SQL Server裏鎖升級的基礎知識,還有它是如何影響執行計劃的。今天,我想進一步談下鎖升級:html
一般在SQL Server裏若是在SQL語句裏你請求的行數超過5000(SELECT,INSERT,UPDATE,DELETE)會發生鎖升級。例如當你再可重複讀隔離級別(Repeatable Read Isolation Level)裏,從表你讀超過5000行數據,鎖升級就會被SQL Server觸發。sql
當你對超過5000行的數據運行UPDATE和DELETE語句,也會觸發鎖升級。做爲反作用,最終你有一個共享(S)或排它(X)表鎖。這確定會傷及你的併發,下降性能和你工做負載的吞吐量。session
鎖升級的整個想法聽起來很簡單,但會有大影響和反作用:若是你不能得到共享或排它表鎖會發生什麼,由於其餘人在表上得到了不兼容的鎖?在這個狀況下,鎖升級應該阻塞麼?但願不是......併發
所以咱們來構建一個簡單的例子,在這裏咱們嘗試重現這個狀況來看下載這個特定狀況下,SQL Server如何反應。下列查詢在Person.Person表裏彙集索引裏的最後一行請求一個X鎖。 app
-- 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
-- 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)。若是鎖升級阻塞的話,狀況會更加糟糕,由於這會無端下降並行查詢的併發!spa
在SQL Server裏鎖升級很是重要,由於它們幫助SQL Server節約裏在鎖管理器裏的哈希表空間。但鎖升級只被SQL Server「嘗試」。若是SQL Server不能進行鎖升級,由於在表層級有不兼容的鎖,什麼也不會發生。鎖升級不能佔用空間,觸發鎖升級的SQL語句也不會阻塞。scala
但願這個特定場景能夠幫你更好的理解SQL Server裏的鎖升級行爲。code
原文連接:
https://www.sqlpassion.at/archive/2016/05/09/lock-escalations-do-they-always-happen/