幾年前,我寫了篇關于閂鎖和為什么SQL Server需要它們的文章。在今天的文章里,我想進一步談下非緩存區閂鎖(Non-Buffer Latches),還有在索引查找操作期間,SQL Server如何使用它們。在這里你會學到稱為閂鎖耦合(Latch Coupling)的概念。
索引查找操作(Index Seek Operations)
正如你知道的,SQL Server使用掃描(Scan)和查找(Seek)操作在索引(聚集和非聚集索引)里訪問數據。這里的查找操作使用B樹的導航結構在葉子節點查找特定的記錄。下圖展示了這個概念。
在這個例子里,SQL Server讀取索引根頁,在層級下的索引頁,最后在葉子級別讀取數據頁。每次SQL Server在緩存池里訪問這個頁,這個頁需要獲得共享閂鎖(Shared Latch)。共享閂鎖是至關重要的,因為在內存里,它讓當下處理的頁只讀:
- 每個排它閂鎖(Exclusive Latch)和共享閂鎖不兼容。
因此請求一個排它閂鎖會阻塞,SQL Server會提示你有個PAGELATCH_EX等待類型。
現在我們來看下在查找操作期間,在索引頁上,SQL Server如何獲取和釋放這些閂鎖。下列代碼展示了對于一個特定的會話ID,可以捕獲latch_acquired和latch_released事件的擴展事件會話(根據實際情況修改會話ID)。
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。是的,擴展事件是自表述的……
下一步,我現在用一個表來進行聚集索引查找操作,在那個表上我已經創建了聚集索引,在導航層級里包含三層(包含葉子層)。
閂鎖耦合實戰(Latch Coupling in Action)
擴展事件會話向你展示了,在聚集索引查找操作期間,對于整個會話需要那個緩存閂鎖(只要你修改的會話ID是正確的……)。當你查看輸出時,你會看到我們已經捕獲了6個事件:3個latch_acquired事件, 和3個latch_released事件。
但更有意思的事是SQL Server獲得和釋放這些閂鎖的順序。一般你期望SQL Server在頁上獲得閂鎖,并最后釋放這個閂鎖。但事實并非如此!
我們來詳細看下。首先SQL 在索引根頁(975號頁)上獲得了一個共享閂鎖。在SQL Server處理那個頁后,聚集索引查找操作在接下來的層級里,繼續讀取請求的頁,并在它上面獲取閂鎖(257號頁)。
注意在索引根頁上獲得的閂鎖還沒有釋放,它還保持獲取!
當在接下來的索引頁上成功獲取閂鎖后,在索引根頁上的閂鎖才會釋放。這個方法稱為閂鎖耦合(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/
![]() |
不含病毒。www.avast.com |