Sql-Server

如何辨識 SQL Server 中發生的非確定性更新?

  • March 5, 2019

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;

UPDATESQL 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``ANYANY``DISTINCT SORT

因此,一種方法是在計劃記憶體中搜尋包含update操作符的所有執行計劃,這些操作符具有使用ANYor的後代運算符,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"]') )) 

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