Sql-Server

MERGE 語句失敗:如何使用 XEvents 進行監視並專門獲取準備好的語句的參數值?

  • December 13, 2019

我的問題

我正在執行 SQL Server 2017,並希望使用如下所示的 MERGE 語句調查錯誤

MERGE INTO table
USING 
   (SELECT ? AS Search_Col) AS SRC
   ON table.blobTask_id = SRC.Search_Col
WHEN MATCHED THEN
   UPDATE SET
   x= ?,
   y= ?,
   z= ? 
WHEN NOT MATCHED THEN
   INSERT (blobTask_id ,x, y, z, ) 
   VALUES (SRC.Search_Col, ?, ?, ?)

錯誤是

違反 UNIQUE KEY 約束“IX_U_CCC_GDV_CONTENTCCC__blobTask_id”。無法在對象“表”中插入重複鍵。該語句已終止。

我知道 MERGE 語句帶有幾個陷阱。但是我可以排除典型問題(沒有觸發器,表上的數據修改沒有並發)。

奇怪的是,錯誤只是偶爾出現一次,並且再次執行該語句而沒有錯誤。

我的診斷方法

我為有問題的語句的 query_hash 設置了擴展事件會話過濾。Jeremiah Peschka 有一篇很棒的部落格文章,我按照它來做這件事。

目前我的 XEvent 會話如下所示:

CREATE EVENT SESSION [query hash] ON SERVER 
ADD EVENT sqlserver.prepare_sql(
   ACTION(package0.collect_system_time,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.database_name)
   WHERE ([sqlserver].[query_hash]=(6577967268103212561.))),
ADD EVENT sqlserver.sp_statement_completed(SET collect_statement=(1)
   ACTION(package0.collect_system_time,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.database_name,sqlserver.sql_text)
   WHERE ([sqlserver].[query_hash]=(6577967268103212561.))),
ADD EVENT sqlserver.sql_statement_completed(
   ACTION(package0.collect_system_time,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.database_name)
   WHERE ([sqlserver].[query_hash]=(6577967268103212561.)))
ADD TARGET package0.event_file(SET filename=N'X:\DB_Data\query_hash.xel',max_file_size=(5),max_rollover_files=(5),metadatafile=N'X:\DB_Data\query_hash.xem')
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=5 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)
GO

我的問題

問題是,在這個會話中,我只能得到如下錄音: 事件記錄

不知何故,只有 sp_statement_completed 事件出現。為了調試問題,獲取 SQL 的參數至關重要。

具體問題:如何修改 XEvent 會話以顯示參數值?

我希望從 prepare_sql 事件中獲取該資訊,但它沒有出現在會話中……也許是由於我的過濾器?

一般請求幫助:如果您知道其他有效解決問題和緩解問題的方法,也請告訴我。

非常感謝您的幫助

先感謝您

馬丁

您的合併語句格式不正確,並且將始終插入所有記錄,因此您需要更新它並告訴它插入目標表中不匹配的記錄, WHEN NOT MATCHED如下所示:

MERGE table
USING 
   (SELECT ? AS Search_Col) AS SRC
   ON table.blobTask_id = SRC.Search_Col
WHEN MATCHED THEN
   UPDATE SET
   x= ?,
   y= ?,
   z= ? 
WHEN NOT MATCHED THEN
   INSERT (blobTask_id ,x, y, z, ) 
   VALUES (SRC.Search_Col, ?, ?, ?)

要獲取失敗語句的確切語句和參數,您需要在語句執行之前擷取事件,因為語句失敗,您將不會獲得完整的語句。

CREATE EVENT SESSION [a] ON SERVER 
 ADD EVENT sqlserver.sql_statement_starting(
 ACTION(sqlserver.sql_text))

謝謝@Dan Guzman。rpc_completed 對我來說是缺少的事件。不幸的是,沒有簡單的過濾可能是查詢雜湊,因為沒有與 sp_executesql 過程呼叫相關聯。因此,我選擇過濾 sqltext 本身(可能是一個昂貴的操作,但它有效)。

這是我最後的 XEvent 會話,以防有人可以利用它:

DROP EVENT SESSION [query hash] ON SERVER;
GO
CREATE EVENT SESSION [query hash] ON SERVER 
ADD EVENT sqlserver.sp_statement_completed(SET collect_statement=(1)
   ACTION(package0.collect_system_time,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.database_name,sqlserver.sql_text,sqlserver.session_id)
   WHERE ([sqlserver].[query_hash]=(6577967268103212561.))),
ADD EVENT sqlserver.rpc_completed(
   ACTION(package0.collect_system_time,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.database_name, sqlserver.query_hash)
   --WHERE ([sqlserver].[query_hash]=(6577967268103212561.))
   WHERE sqlserver.sql_text LIKE '%ERGE INTO table%'
   ),
ADD EVENT sqlserver.error_reported(
   ACTION(package0.collect_system_time,sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.database_name,sqlserver.sql_text,sqlserver.session_id)
   WHERE (([error_number]=2627))
   )
ADD TARGET package0.ring_buffer(SET max_events_limit=(100000),max_memory=(512000))
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=5 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)
GO

現在我等待下一個錯誤發生,並在我有一個錯誤後發布結果和解決方案。

引用自:https://dba.stackexchange.com/questions/255563