close
文章出處

前段時間,我寫了一些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
arrow
arrow
    全站熱搜

    AutoPoster 發表在 痞客邦 留言(0) 人氣()