SQL Server裏的閂鎖耦合(Latch Coupling)

幾年前,我寫了篇關於閂鎖和爲何SQL Server須要它們的文章。在今天的文章裏,我想進一步談下非緩存區閂鎖(Non-Buffer Latches),還有在索引查找操做期間,SQL Server如何使用它們。在這裏你會學到稱爲閂鎖耦合(Latch Coupling)的概念。html

索引查找操做(Index Seek Operations)

正如你知道的,SQL Server使用掃描(Scan)和查找(Seek)操做在索引(彙集和非彙集索引)裏訪問數據。這裏的查找操做使用B樹的導航結構在葉子節點查找特定的記錄。下圖展現了這個概念。sql

在這個例子裏,SQL Server讀取索引根頁,在層級下的索引頁,最後在葉子級別讀取數據頁。每次SQL Server在緩存池裏訪問這個頁,這個頁須要得到共享閂鎖(Shared Latch)。共享閂鎖是相當重要的,由於在內存裏,它讓當下處理的頁只讀:緩存

  • 每一個排它閂鎖(Exclusive Latch)和共享閂鎖不兼容。

所以請求一個排它閂鎖會阻塞,SQL Server會提示你有個PAGELATCH_EX等待類型。session

如今咱們來看下在查找操做期間,在索引頁上,SQL Server如何獲取和釋放這些閂鎖。下列代碼展現了對於一個特定的會話ID,能夠捕獲latch_acquired和latch_released事件的擴展事件會話(根據實際狀況修改會話ID)。 sqlserver

CREATE EVENT SESSION LatchTracking ON SERVER 
ADD EVENT sqlserver.latch_acquired
(
    ACTION
    (
        sqlserver.database_id,
        sqlserver.session_id,
        sqlserver.sql_text
    )
    WHERE
    (
        [package0].[equal_uint64]([sqlserver].[session_id],(54)) AND [class]=(28))
    ),
ADD EVENT sqlserver.latch_released
(
    ACTION
    (
        sqlserver.database_id,sqlserver.session_id,sqlserver.sql_text
    )
    WHERE
    (
        [package0].[equal_uint64]([sqlserver].[session_id],(54)) AND [class]=(28))
    )
ADD TARGET package0.event_file
(
    SET filename=N'c:\temp\LatchTracking.xel'
)
WITH
(
    MAX_MEMORY = 4096 KB,
    EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS,
    MAX_DISPATCH_LATENCY = 30 SECONDS,
    MAX_EVENT_SIZE = 0 KB,
    MEMORY_PARTITION_MODE = NONE,
    TRACK_CAUSALITY = OFF,
    STARTUP_STATE = OFF
)
GO

 注意:在「class」屬性上的篩選謂語限制了緩存閂鎖。它們的內部ID是28。是的,擴展事件是自表述的…… ui

下一步,我如今用一個表來進行彙集索引查找操做,在那個表上我已經建立了彙集索引,在導航層級裏包含三層(包含葉子層)。spa

閂鎖耦合實戰(Latch Coupling in Action)

擴展事件會話向你展現了,在彙集索引查找操做期間,對於整個會話須要那個緩存閂鎖(只要你修改的會話ID是正確的……)。當你查看輸出時,你會看到咱們已經捕獲了6個事件:3個latch_acquired事件, 和3個latch_released事件。線程

 

但更有意思的事是SQL Server得到和釋放這些閂鎖的順序。通常你指望SQL Server在頁上得到閂鎖,並最後釋放這個閂鎖。但事實並不是如此!指針

咱們來詳細看下。首先SQL 在索引根頁(975號頁)上得到了一個共享閂鎖。在SQL Server處理那個頁後,彙集索引查找操做在接下來的層級裏,繼續讀取請求的頁,並在它上面獲取閂鎖(257號頁)。code

注意在索引根頁上得到的閂鎖尚未釋放,它還保持獲取!

當在接下來的索引頁上成功獲取閂鎖後,在索引根頁上的閂鎖纔會釋放。這個方法稱爲閂鎖耦合(Latch Coupling)。這個必須的,由於SQL Server在B樹結構裏,跟隨從一個頁到另外一個頁的指針。

在頁處理期間,這個指針必須保持穩定。例如,在此期間不容許被另外一個工做者線程(例如分頁操做)將此指針無效。所以SQL Server在(單線程)索引查找操做期間,同時把持2個閂鎖。下面這個圖片很好的演示了這個重要概念。

 

當SQL Server在下層的頁(頁號257)上成功獲取共享閂鎖後,在索引根頁(頁號975)上的共享閂鎖被釋放。當SQL Server在中間層處理了這個頁後,SQL Server在葉子層級的數據頁(頁號256)上得到共享閂鎖,而後並在上層的頁(頁號257)上釋放共享閂鎖。當這個頁成功處理後,最後在頁號265上的共享閂鎖也被釋放。

小結

在這篇文章裏我向你展現了在索引查找操做中,經過所謂的閂鎖耦合概念,SQL Server如何獲取和釋放閂鎖。一個常見的誤解,在查找操做期間,SQL Server只在特定的頁上獲取閂鎖。如你在今天的文章所見,這個並不真的正確。

感謝您的關注!

原文連接

http://www.sqlpassion.at/archive/2016/10/24/latch-coupling-in-sql-server/

相關文章
相關標籤/搜索