MERGE 語句失敗:如何使用 XEvents 進行監視並專門獲取準備好的語句的參數值?
我的問題
我正在執行 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
現在我等待下一個錯誤發生,並在我有一個錯誤後發布結果和解決方案。