SQL Serverがオンラインで予約 状態
FROM
句を指定して更新操作の基準を提供する場合は注意してください。UPDATE
ステートメントの結果が未定義であるFROM
句がステートメントに含まれている場合、その結果は未定義です。つまり、更新される各列オカレンスで使用できる値は1つだけです。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;
SQL Serverは、独自のUPDATE
構文を使用しているときに警告を出しません。 MERGE
ステートメントは、「MERGEステートメントが同じ行を複数回UPDATEまたはDELETEしようとしました。これは、ターゲット行が複数のソース行と一致する場合に発生します。」
あなたの例の実行計画は
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
のスキャンから出力され、一意の行識別子として機能します。次に、Bmk
集計を使用して、@t2
の複数の結合行が追加され、ANY
ごとに任意の行に折りたたまれます。 計画によっては、ANY
集合体をDISTINCT SORT
)に置き換える場合があります
したがって、1つの方法は、update
またはDISTINCT SORT
のいずれかを使用して子孫演算子を持つANY
演算子を含むすべての実行プランをプランキャッシュで検索することです。更新を行う前に、重複を恣意的に削除していました。
これは、他の理由で計画に表示される可能性があるが、いくつかの実行可能な候補を検討する必要があるので、決してばかげているとは言えません。
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"]') ))