Database
 sql >> Datenbank >  >> RDS >> Database

Wenn Sie indizierte Ansichten und MERGE verwenden, lesen Sie dies bitte!

Fellow MVP Jamie Thomson wies kürzlich darauf hin, dass es in SQL Server einen „falsche Ergebnisse“-Fehler gibt, der sich manifestieren kann, wenn die folgenden Bedingungen zutreffen:

  • Sie haben eine indizierte Ansicht, die mindestens zwei Tabellen verknüpft;
  • diese Tabellen sind in beide Richtungen durch einen einspaltigen Fremdschlüssel eingeschränkt;
  • Sie führen Aktualisierungen der Basistabelle(n) mit MERGE durch was sowohl UPDATE enthält und (LÖSCHEN oder EINFÜGEN ) Aktionen; und,
  • Sie geben anschließend Abfragen aus, die auf den Index der Ansicht verweisen (absichtlich oder nicht).

Leider enthält der Knowledge Base-Artikel, der das Problem beschreibt (KB-Nr. 2756471), ziemlich wenige Details. Sie sagen Ihnen nicht, wie Sie das Problem reproduzieren können oder worauf Sie speziell achten sollten, um festzustellen, ob Sie davon betroffen sind. und sie erwähnen nicht einmal MERGE (was eigentlich der Kern des Problems ist, nicht NOEXPAND , und kein einfaches Update). Es gibt einige zusätzliche Details im Connect-Element, die den Fix bewirkt haben; hoffentlich wird der KB-Artikel in Kürze mit weiteren Details aktualisiert.

In der Zwischenzeit sehen Sie möglicherweise falsche Daten – oder besser gesagt, veraltete Daten :Die Abfrage zeigt möglicherweise die alte Version der aktualisierten Zeile(n) an! Ich habe ein paar Minuten damit verbracht, dieses Szenario in AdventureWorks zu reproduzieren, und bin kläglich gescheitert. Zum Glück hat Paul White (Blog | @SQL_Kiwi) einen herausragenden Beitrag geschrieben, der das Szenario beschreibt und eine vollständige Repro des Problems zeigt.

Ich glaube nicht, dass ich betonen kann, wie ernst das ist.

Sicherlich verwenden Millionen von Kunden indizierte Ansichten, viele von ihnen haben ihren DML-Code migriert, um MERGE zu verwenden , und eine große Anzahl davon sind in der Enterprise Edition (oder nicht, verwenden aber NOEXPAND Hinweis oder verweisen direkt auf den Index). Paul wies schnell darauf hin, dass NOEXPAND ist nicht erforderlich, um das Problem in der Enterprise Edition zu reproduzieren, und entdeckte auch viele der anderen Details, die zum Reproduzieren des Fehlers erforderlich sind.

Dieser Beitrag soll Jamies oder Pauls Beiträgen keinen Donner stehlen; nur ein Versuch, die Besorgnis zu wiederholen und das Bewusstsein für dieses Problem zu schärfen. Wenn Sie die Angewohnheit haben, kumulative Updates zu ignorieren, auf Service Packs zu warten, und die Möglichkeit besteht, dass dieses Problem Sie gerade jetzt betrifft, sind Sie es sich selbst schuldig, ganz zu schweigen von Ihren Stakeholdern und Kunden dieses Problem ernst.

Also, was sollten Sie tun?

Nun, was Sie als Nächstes tun, hängt davon ab, welche Version und Edition von SQL Server Sie ausführen und ob der Fehler Sie tatsächlich betrifft (oder könnte).

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

    Ihre Optionen, wenn Sie einen dieser Builds verwenden:

    1. Sie sollten auf das neueste kumulative Update für Ihren Zweig aktualisieren:
      Zweig In CU behoben Bauen Mindest-Build erforderlich
      um das Update anzuwenden

      KB-Artikel
      (Download)
      2008 Service Pack 3 CU #8 10.00.5828 10.00.5500 KB #2771833
      2008 R2 Service Pack 1 CU Nr. 10 10.50.2868 10.50.2500 KB #2783135
      2008 R2 Service Pack 2 CU Nr. 4 10.50.4270 10.00.4000 KB #2777358
      RTM 2012 CU Nr. 5 11.00.2395 11.00.2100 KB #2777772
      2012 Service Pack 1 CU Nr. 2 11.00.3339 11.00.3000 KB #2790947

      Tabelle 1:Builds, die den Fix enthalten

    2. Wenn Sie den Fix nicht anwenden, müssen Sie alle Verweise auf Ihre Ansichten testen, um sicherzustellen, dass sie in allen Fällen korrekte Ergebnisse zurückgeben – auch nachdem Sie die Basistabellen mit MERGE . Wenn dies nicht der Fall ist (oder Sie vermuten, dass sie später betroffen sein könnten), sollten Sie den gruppierten Index für alle betroffenen Ansichten neu erstellen (oder die indizierten Ansichten mithilfe von DBCC CHECKTABLE reparieren). , wie Paul es in seinem Beitrag beschrieben hat), und verwenden Sie nicht mehr MERGE gegen diese Tabellen, bis Sie den Fix angewendet haben. Wenn Sie weiterhin MERGE verwenden gegen die Basistabellen, bereiten Sie sich darauf vor, die Ansichten weiter zu reparieren, um das Problem zu vermeiden.
    3. Eine schnellere Lösung wäre, zu verhindern, dass die beschädigte indizierte Ansicht überhaupt verwendet wird, indem Sie eine der folgenden erforderlichen Methoden verwenden:
      • Wenden Sie den Abfragehinweis OPTION (EXPAND VIEWS) an auf alle relevanten Anfragen;
      • entfernen Sie alle expliziten Verweise auf den Index in der Ansicht;
      • Entfernen Sie in Standard oder anderen Editionen, in denen indizierte Ansichten nicht automatisch abgeglichen werden, alle Instanzen von NOEXPAND .

      Aber dies würde natürlich den Zweck der indizierten Ansicht weitgehend zunichte machen – der Index kann genauso gut gelöscht werden. Allerdings ist es in der Regel besser, langsam die richtigen Ergebnisse zu erzielen, als schnell die falschen Ergebnisse zu erzielen. also vielleicht ist das okay.

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

    Leider befinden Sie sich in einem Build, der nicht mehr im Mainstream-Support ist, und es ist unwahrscheinlich, dass dieses Problem für Sie behoben wird (es sei denn, Sie haben erweiterten Support und machen viel Lärm). Ihre Optionen sind hier also begrenzt – wechseln Sie entweder zu einem unterstützten Zweig gemäß der obigen Tabelle und wenden Sie das kumulative Update an oder wählen Sie eine der anderen zuvor erwähnten Optionen.

    SQL-Server 2000
    SQL-Server 2005

    Nun, die schlechte Nachricht ist, dass Sie sich auch auf einem Build befinden, der nicht mehr unterstützt wird. Die gute Nachricht ist, dass es in diesem speziellen Fall keine Rolle spielt – Sie können MERGE nicht verwenden wie auch immer, dieser Fehler kann Sie also nicht betreffen.

Andere MERGE-Probleme

Leider ist dies bei weitem nicht der erste Fehler, den wir bei MERGE gesehen haben , und es wird wahrscheinlich nicht das letzte sein. Hier ist eine schnelle Auswahl von einem Dutzend MERGE Fehler, die auf Connect noch als aktiv markiert sind:

  • #773895 :MERGE meldet fälschlicherweise Verstöße gegen eindeutige Schlüssel
  • #766165 :MERGE wertet den gefilterten Index pro Zeile aus, nicht nach dem Vorgang, was zu einer Verletzung des gefilterten Index führt
  • #723696 :Einfaches MERGE-Upsert verursacht Deadlocks
  • #713699 :Eine Systemassertionsprüfung ist fehlgeschlagen ("cxrowset.cpp":1528)
  • #699055 :MERGE-Abfragepläne erlauben FK- und CHECK-Einschränkungsverletzungen
  • #685800 :Parametrisiertes DELETE und MERGE erlauben Verletzungen von Fremdschlüsselbeschränkungen
  • #654746 :Merge in SQL2008 SP2 leidet immer noch unter "Versuch, den Wert einer nicht NULL-fähigen Spalte auf NULL zu setzen"
  • #635778 :NOT MATCHED- und MATCHED-Teile einer SQL MERGE-Anweisung sind nicht optimiert
  • #633132 :MERGE IN WITH FILTERED SOURCE funktioniert nicht richtig
  • #596086 :Fehler bei der MERGE-Anweisung, wenn INSERT/DELETE einen gefilterten Index verwendete
  • #583719 :Die MERGE-Anweisung behandelt berechnete Spalten ohne Nullwerte in einigen Szenarien falsch
  • #539084 :MERGE Stmt :Suchbedingung für eine Nicht-Schlüsselspalte und ein ORDER BY in der von der Quelle abgeleiteten Tabelle unterbricht MERGE vollständig

Nun kann es sein, dass einige dieser Fehler tatsächlich behoben wurden, ihr Status aber falsch ist, weil die Schleife zurück zu Connect nicht geschlossen wurde. Selbst wenn das der Fall ist, kann es nicht für alle gelten (und möglicherweise für andere, die ich nicht entdeckt habe).

Darüber hinaus wurde von Dan Guzman gezeigt, dass MERGE ist nicht immun gegen Race Conditions und andere Parallelitätsprobleme. Die Problemumgehung besteht darin, HOLDLOCK zu verwenden (oder eine höhere Isolationsstufe); Es ist jedoch ein verbreiteter Irrglaube, dass MERGE ist vollständig atomar und überhaupt nicht anfällig für dieses Problem. Deshalb frage ich mich laut:wie viele MERGE Anweisungen da draußen beinhalten HOLDLOCK (oder werden unter SERIALIZABLE ausgeführt )? Wie viele wurden gründlich auf Probleme im Zusammenhang mit Parallelität getestet?

Schlussfolgerung

Persönlich finde ich die Syntax großartig (wenn auch entmutigend zu lernen), aber jedes Mal, wenn ein Problem auftaucht, untergräbt es mein Vertrauen in die praktische Anwendbarkeit des Ersetzens bestehender DML durch das neue Konstrukt.

In diesem Sinne möchte ich nicht Chicken Little sein, aber ich würde mich nicht wohl dabei fühlen, jemandem zu empfehlen, MERGE zu verwenden es sei denn, sie implementieren extrem umfassende Tests. Einige dieser Probleme treten auch bei standardmäßigem UPSERT auf Methoden, aber dort sind die Probleme offensichtlicher. MERGE , nur durch seine Einzelaussage-Natur, weckt den Wunsch, an Magie zu glauben. Vielleicht wird es eines Tages liefern, aber im Moment weiß ich, dass es ohne ernsthafte Hilfe nicht in der Lage sein wird, eine Person in zwei Hälften zu zersägen.