Sql-Server
如何辨識 SQL Server 中發生的非確定性更新?
SQL Server 線上預訂狀態
FROM
指定子句以提供更新操作的條件時要小心。UPDATE
如果語句包含的FROM
子句未以這樣一種方式指定,即對於每個更新的列出現只有一個值可用,即如果該UPDATE
語句不是確定性的,則該語句的結果是未定義的。我需要嘗試確定數據庫中發生非確定性更新的情況。在這種情況下,SQL Server 似乎不會引發錯誤或警告。
有誰知道是否有一種簡單的方法可以確定這些問題發生在哪裡,查詢計劃記憶體等?鑑於應用程序的規模和復雜性,進行完整的程式碼審查以辨識這些問題將非常耗時。
在 SQL Server 2008\2017 開發人員版本上測試。
這是一個例子:
declare @t1 table (id int, col int); insert into @t1 values(1,1); declare @t2 table (id int, col int); insert into @t2 values(1,10), (1,20); update t1 set t1.col = t2.col from @t1 t1 join @t2 t2 on t1.id = t2.id; select * from @t1;
UPDATE
SQL Server 在使用其專有語法時不會向您發出警告。該MERGE
語句將引發錯誤“MERGE 語句多次嘗試更新或刪除同一行。當目標行與多個源行匹配時會發生這種情況。”您的範例的執行計劃是
update t1 set t1.col = t2.col from @t1 t1 join @t2 t2 on t1.id = t2.id |--Table Update(OBJECT:(@t1 AS [t1]), SET:(@t1.[col] as [t1].[col] = @t2.[col] as [t2].[col])) |--Stream Aggregate(GROUP BY:([Bmk1000]) DEFINE:([t2].[col]=ANY(@t2.[col] as [t2].[col]))) |--Nested Loops(Inner Join, WHERE:(@t2.[id] as [t2].[id]=@t1.[id] as [t1].[id])) |--Table Scan(OBJECT:(@t1 AS [t1])) |--Table Scan(OBJECT:(@t2 AS [t2]))
該
Bmk
列是從掃描中輸出的,@t1
以充當唯一的行標識符。然後使用聚合添加潛在的多個連接行@t2
並將其折疊為任意一個。在某些情況下,該計劃可能會用一個Bmk``ANY
ANY``DISTINCT SORT
因此,一種方法是在計劃記憶體中搜尋包含
update
操作符的所有執行計劃,這些操作符具有使用ANY
or的後代運算符,DISTINCT SORT
因為這可能表明 SQL Server 在執行更新之前任意刪除了重複項。這遠非萬無一失,因為它們可能出於其他原因出現在計劃中,但應該讓一些可行的候選人進行審查。
WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan') SELECT st.text FROM sys.dm_exec_cached_plans cp CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) qp CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) st WHERE EXISTS(SELECT 1 FROM qp.query_plan.nodes('//Update') upd(n) WHERE 1 IN ( n.exist('//Aggregate[@AggType eq "ANY"]'), n.exist('//RelOp[@LogicalOp eq "Distinct Sort"]') ))