第19/24周 鎖升級(Lock Escalations)

你們好,歡迎回到性能調優培訓。上2個星期咱們已經討論了SQLServer裏的悲觀和樂觀鎖。今天我想談下SQL Server裏對於鎖的一個特殊現象:所謂的鎖升級(Lock Escalations)。在咱們進入那個問題的細節前,我想先談下SQL Server內部使用的鎖層級(Lock Hierarchy)html

鎖層級(Lock Hierarchy)

2個星期前,當咱們開始討論悲觀併發模式(pessimistic concurrency)時,我告訴你SQLServer在記錄層會獲取共享鎖(Shared Locks)和排它鎖(Exclusive Locks)。遺憾的是,這不是所有事實。完整事實是SQL Server會在不一樣粒度(granularities)得到鎖,例如數據庫,不一樣頁,最後在記錄層。SQL Server實現整個所層級(lock hierarchy),以下圖所示:數據庫

一旦你使用一個數據庫,你的會話會在數據庫上得到一個共享鎖(Shared Lock)。那個共享鎖是須要的,所以沒有其餘人能夠刪除數據庫,或還原數據庫備份。這些操做會被阻塞,由於你打開的會話。SQL Server不但在行層上有共享鎖和排它鎖,SQL Server也在表和頁層使用所謂的意向鎖(Intent Locks)安全

  • 在行層有共享鎖(Shared Locks),在表和頁上拿到意向共享鎖(intent shared lock(IS))。
  • 在行層有排它鎖(Exclusive Locks),在表和頁上拿到意向排它鎖(intent exclusive lock(IX))。

意向鎖(Intent Locks)用來做爲1個信號,表示在鎖層級(lock hierarchy)裏(極可能)有1個不兼容的鎖在低一層已得到。意向鎖是關係數據庫主要性能調優。沒有它們的話,鎖管理器須要在低1層徹底進入列表,來決定高1層的鎖是否能夠獲取。若是你在表層有一個意向排它鎖(IX),你就不能在表層得到排它鎖(X),由於有些記錄在表自己裏已是排它鎖(X):在表層得到排它鎖(X)會阻塞,由於在表上已經有意向排它鎖(IX)。併發

遺憾的是這個多粒度鎖並非免費的:在SQL Server裏每一個鎖須要96 bytes,所以會消耗一些內存,SQL Server必須保證沒有查詢使用太多的內存空間,否則的話內存會被耗盡。這就是爲何會有鎖升級(lock escalations)的存在。性能

鎖升級(Lock Escalations)

假設下列情景:你更新散佈在20萬個數據頁上的1百萬條記錄。在那個狀況下,你須要在記錄自己得到1百萬個排它鎖(X),在不一樣頁上得到20萬個意向排它鎖(IX),在表自己上得到1個意向排它鎖(IX),你的查詢合計須要得到1200001,在鎖管理器須要近110M的鎖空間——就只對這個簡單查詢。依據內存佔用這個方法很是危險。所以你在一層一旦得到超過5000個鎖,SQL Server就會觸發鎖升級(Lock Escalations)——例如在記錄層。在那個狀況下,SQL Server升級你個體細密度行鎖爲1個粗顆粒的表鎖:spa

  • 個體X鎖升級爲1個表的X鎖
  • 個體S鎖升級爲1個表的S鎖

下圖演示了鎖升級發生先後的鎖保持狀況:scala

經過鎖升級內存佔用確定會降低——但這也會影響你數據庫的併發!在表上的排它鎖(X)意味着沒有其餘人能夠從你的表讀寫,在表層上的共享鎖(S)意味着你的表是隻讀的,沒有人能夠寫它!你數據庫的吞吐量只會降低!code

當你在1個層得到超過5000個鎖,SQL Server就會觸發鎖升級。這是系統硬碼限定,不一樣經過任何配置選項修改。自SQL Server 2008開始,你能夠經過以下代碼,控制經過ALTER TABLE DDL語句的鎖升級:htm

1 ALTER TABLE MyTableName
2 SET
3 (
4    LOCK_ESCALATION = TABLE -- or AUTO or DISABLE
5 )
6 GO

默認狀況,SQL Server老是升級到表級別(Table選項)。若是你設置升級選項爲AUTO,當你的表是分區的話,SQL Server能夠升級到分區級別。但對這個選項,你要很是仔細,由於若是你用錯誤的順序訪問分區,它會致使死鎖。使用DISABLE選項,對錶你停用了鎖升級——這會帶來剛纔提到的全部各個反作用(內存消耗)。如今的問題是,你如何高效修改或刪除5000條記錄而不觸發鎖升級?blog

  1. 逐步更新/刪除少於5000條記錄(例如在WHILE循環裏)
  2. 若是表分區的話,使用分區交換
  3. 臨時停用鎖升級,但要注意同時的內存耗用

小結

鎖升級(Lock Escalations)是SQL Server提供的安全保障。它們爲何存在有個好理由,但當升級發生時,這個會引入更少併發的反作用。所以當你在寫一次處理超過5000條記錄的代碼時要很是仔細。或許你能夠逐步處理這些記錄,而不是用1個大的UPDATE/DELETE語句。若是你想了解更多鎖升級信息,能夠看下我之前寫一篇文章《鎖升級》。

下週咱們繼續SQL Server裏的鎖和阻塞,講下死鎖,還有SQL Server如何處理它們。請繼續關注!

圍觀PPT:

1007_19_鎖升級.rar

相關文章
相關標籤/搜索