SQL Server統計信息更新會被阻塞或引起會話阻塞嗎?
2025-02-08 16:54 瀟湘隱者 閱讀(681) 評論(4) 收藏 舉報在SQL Server數據庫中,統計信息更新(UPDATE STATISTICS)會被其它會話阻塞嗎?統計信息更新(UPDATE STATISTICS)會引起其它會話阻塞嗎?在回答這兩個問題前,我們必須搞清楚,統計信息更新這個操作期間會申請/持有那些鎖。如果弄清楚了這些,那么我們就能很容易回答這兩個問題了。如果要弄清楚統計信息更新會申請/持有那些鎖,我們可以用SQL腳本或SQL Server Profiler工具來查詢/定位相關的鎖信息
SQL腳本方式
SELECT * FROM sys.dm_tran_locks
WHERE request_session_id=xxx; --xxx用具體的會話ID替換
SELECT resource_type ,
resource_subtype ,
resource_description ,
resource_associated_entity_id ,
request_mode ,
request_type ,
request_status ,
request_session_id
FROM sys.dm_tran_locks
WHERE request_session_id = xxx;
用SQL腳本的話,不太容易捕捉到統計信息更新(UPDATE STATISTICS)整個過程中申請的所有相關鎖信息,而且小表的統計信息更新速度非常快(時間短到你來不及去查詢相關鎖信息,有些鎖就已經申請成功,并釋放了,可能統計信息更新都已經完成了),如果要實驗的話,可能需要構造一個很大的表。這種方式還是有一些缺陷與不足。
SQL Server Profiler跟蹤方式
使用SQL Server Profiler工具追蹤更新統計信息期間會申請/持有哪一些鎖。這種方式比較容易捕捉到整個過程中所有相關的鎖申請與鎖釋放的詳細信息,而且用SQL Server Profiler跟蹤鎖的申請與釋放也非常方便。個人推薦使用這種方式。
下面我們打開一個會話窗口,找出會話ID(當前測試環境會話ID為53),然后使用SQL Server Profiler跟蹤會話ID=53的鎖的申請與釋放(Lock:Acquired, Lock:Released),此處SQL Server Profiler的相關操作細節略過。然后在會話窗口執行下面語句
UPDATE STATISTICS TEST WITH FULLSCAN,ALL;
如下部分截圖所示,我們可以看到在統計信息更新期間,數據庫會在相關對象上請求架構穩定鎖(Sch-S)、架構修改鎖(Sch-M)、共享鎖(S),排它鎖(X),意向排他鎖(IX),更新鎖(U)等,整個過程會有較多的鎖申請與鎖釋放。

從上面實驗可以看出,在 SQL Server 中,更新統計信息可能會申請持有很多類型的鎖,那么我來一項項分析,在分析之前,我們來看一下鎖的兼容矩陣,如果對這方面知識有點模糊不清的,正好可以重溫一下這方面的知識點:

注意:除了架構修改鎖 (Sch-M)之外,架構穩定鎖 (Sch-S) 與所有鎖定模式都兼容。而Sch-M 鎖與所有鎖定模式都不兼容。
1. 共享鎖(S)
從實驗數據來看,共享鎖都發生在統計信息元數據對象上。這些元數據對象,如下截圖所示,分別為sysschobjs和sysobjvalues,當然還有OBJECT_ID=0 OBJECTID2=xxxx的數據頁或數據行。

SELECT t.object_id AS ObjectID,
OBJECT_NAME(t.object_id) AS ObjectName,
SUM(u.total_pages) * 8 AS Total_Reserved_kb,
SUM(u.used_pages) * 8 AS Used_Space_kb,
u.type_desc AS TypeDesc,
MAX(p.rows) AS RowsCount
FROM sys.allocation_units AS u
JOIN sys.partitions AS p ON u.container_id = p.hobt_id
JOIN sys.objects AS t ON p.object_id = t.object_id
where u.allocation_unit_id=281474980642816
GROUP BY t.object_id,
OBJECT_NAME(t.object_id),
u.type_desc
ORDER BY Used_Space_kb DESC,
ObjectName;
注意:查詢條件中用實際具體的OBJECTID2的值替換。
從鎖的兼容性來分析的話,這時發生阻塞與被阻塞的可能性是存在的,統計信息更新期間,在申請共享鎖時,某些操作在元數據對象上持有意向排他共享鎖(SIX)、意向排它鎖(IX)、排它鎖(X),例如并發的會話跟新統計數據等操作,實際場景中,統計信息更新很少在發生申請共享鎖時阻塞其它會話與被其它會話阻塞。
2. 架構穩定性鎖(Sch-S)
當UPDATE STATISTICS時,SQL Server 會獲取架構穩定鎖(Sch-S)。這里不僅僅是統計信息更新涉及的相關對象還包括統計信息元數據對象,都會獲取Sch-S鎖,而對于架構穩定鎖(Sch-S)有下面一些規則:
允許其他會話繼續讀取或修改數據(如 SELECT、INSERT、UPDATE)。 僅阻塞需要修改表結構的操作(如 ALTER TABLE、CREATE INDEX),因為這些操作需要架構修改鎖(Sch-M),與架構穩定鎖(Sch-S)不兼容。
此時,除非有并發的會話對表結構進行修改(DDL)或者并發會話在進行統計信息更新操作,此時剛好持有 Sch-M 鎖,那么就可能會被阻塞。 我們會結合架構修改鎖(Sch-M)構造測試案例。
3. 架構修改鎖(Sch-M)
當更新統計信息時,SQL Server 會嘗試獲取統計信息元數據對象上的架構修改鎖(Sch-M)。這種鎖用于確保在更新統計信息的過程中,其他會話不會對統計信息進行修改。如果其他會話已經持有與 Sch-M 不兼容的鎖(如架構穩定性鎖 Sch-S),則更新統計信息的操作可能會被阻塞。
這些元數據對象,如下截圖所示,分別為sysschobjs和sysobjvalues等對象。

那么我們簡單構造一下統計信息更新被阻塞的案例,如下所示
--會話58中執行下面語句,模擬事務正在修改表結構(DDL),此時事務未提交/事務正在執行階段
begin tran
alter table test add kk varchar(30);
--rollback;
--會話53中執行下面語句更新統計信息
UPDATE STATISTICS TEST WITH FULLSCAN,ALL;
在會話窗口監控阻塞情況,如下所示,對表進行DDL操作時,會阻塞統計信息的更新,此時更新統計信息的會話的等待類型為LCK_M_SCH_S,意味著會話53正在等待獲取架構穩定鎖(Sch-S), 其實反過來,更新統計信息也會阻塞一些會話對相關表進行DDL操作。此時對相關表進行DDL操作時。個人也構造了另外一個大表測試案例進行了驗證。有興趣也可以驗證一下。此處略過。


4. 意向排它鎖(IX)與排它鎖(X)與更新鎖(U)
在更新統計信息時,SQL Server 還可能會對相關表(例如,sysobjvalues)中的數據行或頁獲取行鎖(X、U 等)或頁鎖(IX、IU 等)。這些鎖用于確保在采樣數據時,數據不會被其他事務修改。如果有并發的DDL或統計信息跟新的話,也有可能導致阻塞與被阻塞。但是實際生產環境中,這種可能性非常小。另外,在表TEST進行統計信息更新時,也會在TEST上有一個短暫的排它鎖(X),它的子類型(Resource subtype)為UPDSTATS,根據官方文檔[1],只要子類型不同(不同的子類型彼此之間不會沖突),它是不會阻塞表上的DML操作的,除非另外一個會話也在更新統計信息。這種概率微乎其微。
此處附上官方文檔的內容:
Represents a subtype of resource_type. Acquiring a subtype lock without holding a non-subtyped lock of the parent type is technically valid. Different subtypes do not conflict with each other or with the non-subtyped parent type. Not all resource types have subtypes.
結論總結
統計信息更新可能被其它會話阻塞,統計信息更新也有可能阻塞其它會話。當統計信息更新時,會獲取統計信息元數據對象上的架構修改鎖(Sch-M)。如果其他會話已經鎖定了同一對象,或者需要在統計信息元數據對象上獲取架構穩定性鎖(Sch-S)來編譯查詢的會話,可能會被阻塞。但是這種場景比較少;另外不要同時做DDL(修改表結構、創建維護索引)和統計信息更新操作,不要并發的去做統計信息更新(很少有這種場景)。絕大部分場景下,是可以大膽地執行統計信息更新操作,它不會阻塞數據操作(DML),不用擔心它阻塞了其它會話或被阻塞的。
1: https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-tran-locks-transact-sql?view=sql-server-ver16&redirectedfrom=MSDN
浙公網安備 33010602011771號