前些天某個SQL Server數據庫的錯誤日志爆出如下錯誤:
Timeout occurred while waiting for latch: class 'ACCESS_METHODS_DATASET_PARENT', id 00000009A5670C58, type 4, Task 0x0000000B655BC508 : 188, waittime 300,
flags 0x1a, owning task 0x00000000170DC748. Continuing to wait.
第一感覺是並行查詢的問題,於是翻筆記查看'ACCESS_METHODS_DATABASE_PARENT'到底是什么等待事件,可以參考sys.dm_os_latch_stats的官網解釋來了解一二。
ACCESS_METHODS_DATASET_PARENT -- Used to synchronize child dataset access to the parent dataset during parallel operations.
官網的解釋比較含糊,其實這個等待事件的本質是:SQL Server在執行TotalsSubTree超過查詢閾值cost(默認為5)的SQL時會使用並行來完成,即多個threads並行完成一個SQL的查詢,這樣就需要各個線程進行信息交互以便實現一致性,如果SQL執行的時間很長,那么就需要長時間的獲取latch,因此產生這種等待事件,其本質還是因為SQL太爛引起的,需要進行SQL優化。
寫SQL來抓取引發問題的業務SQL,為方便起見創建為sp存儲過程:
USE [master]
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE procedure [dbo].[sp_findtask](@parent_task_address varbinary(8))
as
BEGIN
SELECT
t.spid,t.lastwaittype,t.open_tran,t.status,t.hostname,t.program_name,t.loginame,dc.text
FROM master.sys.sysprocesses t cross apply master.sys.dm_exec_sql_text(t.sql_handle) dc
WHERE spid in (select distinct session_id from sys.dm_os_tasks where parent_task_address=@parent_task_address)
END
GO
涉及到的幾個視圖:sys.sysprocesses,sys.dm_os_tasks都可以通過官網查到相關列的說明,這里不再詳述。對於SQLOS任務調度涉及的概念參考:SQLOS任務調度算法
這樣下次出現問題,只要能從錯誤日志中快速找到owning task的address(就是sys.dm_os_tasks中的parent_task_address列),就可以得到問題SQL的詳細信息了。
在本例中我們先去找由於latch timeout生成的系統轉儲文件,然后再用windbg進行分析即可。由於SQL Server只會在第一次報出latch timeout時生成轉儲文件,我們可以設置838trace來使每次報錯都生成dump,以便獲取更准確和完整的信息。
dbcc traceon(838,-1)