[FIX] 自己結合を伴う更新によって間違った数の行が更新される

この記事は、以前は次の ID で公開されていました: JP285870
この資料は、アーカイブされました。これは "現状のまま" で提供され、更新されることはありません。
現象
次の条件が当てはまる場合、UPDATE 操作によって変更される行の数が正しくないことがあります。
  • クエリでテーブル TabA の列 ColA を更新する場合
  • このクエリで、別名 TabB を使用して TabA を再び参照する場合
  • クエリのどこかに TabB.ColA への参照が存在する場合
  • TabA の更新される列が、いずれもインデックス列ではない場合
  • ハッシュ結合またはマージ結合が使用されている場合
原因
クエリ プランの UPDATE 演算子の下に必要な Table Spool が含まれていない場合があります。この Table Spool は、Halloween Protection を提供するのに必要なものです。
解決方法
この問題を解決するために、SQL Server 2000 及び SQL Server 7.0 の最新の Service Pack の適用をお願いいたします。
最新の SQL Server サービスパックのダウンロードおよびインストールについて詳しくは以下をご覧下さい。

http://www.microsoft.com/japan/sql/download/default.asp (日本語版)
http://www.microsoft.com/sql/downloads/default.htm (英語版)
回避策
この問題を回避するには、次の手順を実行します。
  • OPTION(LOOP JOIN) を使用して、ループ結合を強制します。

    または

  • 更新された列にインデックスを追加します。
状況
弊社では、これを本資料の冒頭に記述した弊社製品の問題として確認しています。

SQL Server 2000

この問題は、Microsoft SQL Server version 2000 Service Pack 1 で修正されています。

SQL Server 7.0

この問題は、Microsoft SQL Server version 7.0 Service Pack 4 で修正されています。
詳細
Halloween Protection は、UPDATE 操作によってテーブル内の行の物理的な位置が変更されるという状況を防ぐために必要です。このような状況の結果として、1 つの論理操作のコンテキスト内で同じ行が複数回アクセスされるという発生してはならない現象が起こる場合があります。この不具合の条件に当てはまる場合、SQL Server オプティマイザは、適切な Halloween Protection を持つプランを作成しないことがあります。

次のサンプル コードを実行すると、この問題が発生します。
set nocount oncreate table test(id int, pid int, fn varchar(256), rn varchar(8))godeclare @c intset @c = 1insert into test values(0, NULL, 'root', 'root')while @c < 10begin   insert into test values(@c, @c-1, NULL, cast(@c as varchar(8)))   set @c = @c + 1endcreate unique clustered index idx_c_id on test(id)goupdate testset fn = parent.fn + '/' + test.rnfrom test(index=0) , test parent(index=0)where test.pid = parent.id and test.fn is NULL --  and parent.fn <> ''option(hash join,force order)
更新後のテーブルの正しい内容は次のとおりです。

正しい結果 :
id          pid         rn       fn                                                                                                                                                                                                                                                               ----------- ----------- -------- ---- 0           NULL        root     root1           0           1        root/1
修正プログラムを適用する前の結果は、次のとおりです。

正しくない結果 :
id          pid         rn       fn                                                                                                                                                                                                                                                               ----------- ----------- -------- ----0           NULL        root     root1           0           1        root/12           1           2        root/1/23           2           3        root/1/2/34           3           4        root/1/2/3/45           4           5        root/1/2/3/4/56           5           6        root/1/2/3/4/5/67           6           7        root/1/2/3/4/5/6/78           7           8        root/1/2/3/4/5/6/7/89           8           9        root/1/2/3/4/5/6/7/8/9
関連情報
この資料は米国 Microsoft Corporation から提供されている Knowledge Base の Article ID 285870 (最終更新日 2001-06-15) をもとに作成したものです。

この資料に含まれているサンプル コード/プログラムは英語版を前提に書かれたものをありのままに記述しており、日本語環境での動作は確認されておりません。

プロパティ

文書番号:285870 - 最終更新日: 01/16/2015 21:25:59 - リビジョン: 2.1

Microsoft SQL Server 7.0 Standard Edition, Microsoft SQL Server 2000 Standard Edition

  • kbnosurvey kbarchive _ik kbbug kbfix kbsqlserv2000bug kbsqlserv700bug KB285870
フィードバック