sql >> データベース >  >> RDS >> Database

インデックス付きビューとMERGEを使用している場合は、こちらをお読みください。

    MVPのJamieThomsonは最近、次の条件が当てはまる場合に現れる可能性のある「間違った結果」のバグがSQLServerにあることを指摘しました。

    • 少なくとも2つのテーブルを結合するインデックス付きビューがあります;
    • これらのテーブルは、単一列の外部キーによってどちらの方向にも制約されます。
    • MERGEを使用してベーステーブルの更新を実行します これには、 UPDATEの両方が含まれます および( DELETE またはINSERT ) 行動;そして、
    • その後、ビューのインデックスを参照するクエリを発行します(意図的かどうかは関係ありません)。

    残念ながら、問題を説明しているナレッジベースの記事(KB#2756471)は、詳細がかなりわかりにくいです。問題を再現する方法や、具体的には、これが自分に影響を与えるかどうかを確認するために何を探す必要があるかについては説明していません。そして彼らはMERGEについても言及していません (これは実際には問題の核心であり、 NOEXPAND ではありません 、単純な更新ではありません)。修正をもたらしたConnectアイテムにはいくつかの追加の詳細があります。 KBの記事がまもなく更新されて詳細が表示されることを願っています。

    その間、表示される可能性のある結果は誤ったデータです。つまり、古いデータ :クエリにより、更新された行の古いバージョンが表示される場合があります。このシナリオをAdventureWorksで再現しようと数分を費やしましたが、惨めに失敗しました。ありがたいことに、Paul White(ブログ| @SQL_Kiwi)は、シナリオを説明し、問題の完全な再現を示す優れた投稿を書きました。

    これがどれほど深刻かを強調することはできないと思います。

    確かに何百万もの顧客がインデックス付きビューを使用しており、それらの多くはDMLコードを MERGEを使用するように移行しています。 、およびそれらの多くはEnterprise Edition上にあります(またはそうではありませんが、 NOEXPANDを使用しています ヒントまたはインデックスを直接参照しています)。 Paulは、 NOEXPANDをすぐに指摘しました。 Enterprise Editionで問題を再現する必要はなく、バグを再現するために必要な他の多くの詳細も発見しました。

    この投稿は、ジェイミーまたはポールの投稿から雷を盗むことを意図したものではありません。懸念を繰り返し、この問題の認識を高めるための試みにすぎません。累積的な更新を無視し、サービスパックを待つことを選択する習慣があり、この問題が今あなたに影響を与える可能性がある場合は、利害関係者や顧客は言うまでもなく、自分自身に責任を負います。この問題は真剣に。

    では、どうすればよいですか?

    次に何をするかは、実行しているSQL Serverのバージョンとエディション、およびバグが実際に影響を与えるかどうか(または影響を与える可能性があるかどうか)によって異なります。

      SQL Server 2008 SP3
      SQL Server 2008 R2 SP1 / SP2
      SQL Server 2012 RTM / SP1

      これらのビルドのいずれかを使用している場合のオプション:

      1. ブランチの最新の累積的な更新に更新する必要があります:
        ブランチ CUで修正 ビルド 更新を適用するには
        最小限のビルドが必要です

        KB Article
        (ダウンロード)
        2008サービスパック3 CU#8 10.00.5828 10.00.5500 KB#2771833
        2008 R2 Service Pack 1 CU#10 10.50.2868 10.50.2500 KB#2783135
        2008 R2 Service Pack 2 CU#4 10.50.4270 10.00.4000 KB#2777358
        2012 RTM CU#5 11.00.2395 11.00.2100 KB#2777772
        2012サービスパック1 CU#2 11.00.3339 11.00.3000 KB#2790947

        表1:修正を含むビルド

      2. 修正を適用しない場合は、ビューへのすべての参照をテストして、 MERGE 。そうでない場合(または後で影響を受ける可能性があると思われる場合)、影響を受けるすべてのビューでクラスター化インデックスを再構築する(または DBCC CHECKTABLE を使用してインデックス付きビューを修復する)必要があります。 、Paulが彼の投稿で説明しているように)、 MERGEの使用を停止します 修正を適用するまで、これらのテーブルに対して。 MERGEを引き続き使用する場合 ベーステーブルに対して、問題を回避するためにビューの修復を続行する準備をします。
      3. より迅速な修正は、必要な次の方法のいずれかを使用して、破損したインデックス付きビューがまったく使用されないようにすることです。
        • クエリヒントを適用するOPTION(EXPAND VIEWS) 関連するすべてのクエリに;
        • ビューのインデックスへの明示的な参照を削除します。
        • インデックス付きビューが自動的に照合されないStandardまたはその他のエディションでは、 NOEXPANDのすべてのインスタンスを削除します 。

        しかし、もちろん、これはインデックス付きビューの目的を大きく損なうことになります。インデックスを削除するだけの場合もあります。とはいえ、通常は、間違った結果をすばやく取得するよりも、正しい結果をゆっくり取得する方が適切です。だから多分それは大丈夫です。

      SQL Server 2008 RTM / SP1 / SP2
      SQL Server 2008 R2 RTM

      残念ながら、現在主流のサポートが終了しているビルドを使用しているため、この問題が修正される可能性はほとんどありません(拡張サポートを使用していて、多くの騒ぎを起こさない限り)。したがって、ここではオプションが制限されます。上記の表に従ってサポートされているブランチに移動して累積的な更新を適用するか、前述の他のオプションのいずれかを選択してください。

      SQL Server 2000
      SQL Server 2005

      悪いニュースは、サポートされなくなったビルドも使用していることです。幸いなことに、この特定のケースでは問題はありません。 MERGEは使用できません。 とにかく、このバグはあなたに影響を与えることはできません。

    その他のMERGEの問題

    残念ながら、これは MERGEで見た最初のバグとはほど遠いものです。 、そしてそれはおそらく最後ではないでしょう。これがダースのクイックセレクションです MERGE Connectでまだアクティブとしてマークされているバグ:

    • #773895:MERGEが一意の主要な違反を誤って報告する
    • #766165:MERGEは、操作後ではなく、行ごとにフィルター処理されたインデックスを評価します。これにより、フィルター処理されたインデックス違反が発生します
    • #723696:デッドロックを引き起こす基本的なMERGEアップサート
    • #713699:システムアサーションチェックに失敗しました( "cxrowset.cpp":1528)
    • #699055:MERGEクエリプランでは、FKおよびCHECK制約違反が許可されます
    • #685800:パラメータ化されたDELETEとMERGEは外部キー制約違反を許可します
    • #654746:SQL2008 SP2でのマージでは、「NULL不可の列の値をNULLに設定しようとしています」という問題が発生します
    • #635778:SQLMERGEステートメントのNOTMATCHEDおよびMATCHED部分が最適化されていません
    • #633132:フィルターされたソースとのマージが正しく機能しない
    • #596086:INSERT/DELETEがインデックスを使用およびフィルタリングした場合のMERGEステートメントのバグ
    • #583719:MERGEステートメントは、一部のシナリオでnull許容でない計算列を誤って処理します
    • #539084:MERGE Stmt:非キー列の検索条件とソース派生テーブルのORDER BYは、MERGEを完全に中断します

    現在、これらのバグの一部は実際に修正されている場合がありますが、Connectへのループバックが閉じられていないため、ステータスが間違っています。たとえそうだとしても、それがすべての人に当てはまるわけではありません(そして、私が明らかにしなかった他の人にも当てはまる可能性があります)。

    さらに、DanGuzmanによってMERGE 競合状態やその他の同時実行の問題の影響を受けません。回避策は、 HOLDLOCKを使用することです。 (またはより高い分離レベル);ただし、 MERGEというのはよくある誤解です。 完全にアトミックであり、この問題が発生する可能性はまったくありません。したがって、私は声を出して疑問に思います:いくつの MERGE そこにあるステートメントには、 HOLDLOCKが含まれます (または SERIALIZABLEで実行されています )?並行性に関連する問題について徹底的にテストされたものはいくつありますか?

    結論

    個人的には、構文は素晴らしいと思いますが(学ぶのは大変ですが)、問題が発生するたびに、既存のDMLを新しい構成に置き換える実用性に対する自信が失われます。

    そのことを念頭に置いて、Chicken Littleになることはありませんが、 MERGEの使用を誰かに勧めるのは気が進まないでしょう。 非常に包括的なテストを実装しない限り。これらの問題のいくつかは、標準の UPSERTにも存在します 方法論ですが、問題はそこでより明白です。 MERGE 、単にその単一のステートメントの性質を通して、あなたは魔法を信じたくなります。いつかは配達されるかもしれませんが、今のところ、深刻な助けがなければ半分の人を見ることができないでしょう。


    1. SQLServerを使用するためのAzure仮想マシン

    2. SQLステートメントまたはストアドプロシージャから外部データベースに接続するにはどうすればよいですか?

    3. Mysqlで1つのデータベーステーブルから別のデータベーステーブルにデータを挿入する方法

    4. PostgreSQLネストされたJSONクエリ