sql >> Database >  >> RDS >> Database

Als u geïndexeerde weergaven en MERGE gebruikt, lees dit dan alstublieft!

Collega MVP Jamie Thomson wees er onlangs op dat er een "verkeerde resultaten"-bug in SQL Server zit die zich kan manifesteren wanneer aan de volgende voorwaarden wordt voldaan:

  • U heeft een geïndexeerde weergave die ten minste twee tabellen samenvoegt;
  • die tabellen worden in beide richtingen beperkt door een externe sleutel met één kolom;
  • je voert updates uit aan de basistabel(len) met behulp van MERGE die zowel UPDATE . bevat en (VERWIJDEREN of INSERT ) acties; en,
  • je geeft vervolgens zoekopdrachten uit die verwijzen naar de index in de weergave (al dan niet opzettelijk).

Helaas bevat het Knowledge Base-artikel dat het probleem beschrijft (KB #2756471) vrij weinig details. Ze vertellen u niet hoe u het probleem kunt reproduceren, of zelfs waar u specifiek naar moet zoeken om te zien of dit u treft; en ze maken niet eens melding van MERGE (wat eigenlijk de kern van het probleem is, niet NOEXPAND , en geen simpele update). Er zijn enkele aanvullende details in het Connect-item dat tot de oplossing heeft geleid; hopelijk zal het KB-artikel binnenkort worden bijgewerkt met meer details.

In de tussentijd kan het resultaat dat u ziet onjuiste gegevens zijn - of beter gezegd, verouderde gegevens :De zoekopdracht kan u de oude versie van de bijgewerkte rij(en) tonen! Ik heb een paar minuten besteed aan het proberen om dit scenario in AdventureWorks te reproduceren, maar faalde jammerlijk. Gelukkig heeft Paul White (blog | @SQL_Kiwi) een uitstekende post geschreven waarin hij het scenario beschrijft en een volledige repro van het probleem laat zien.

Ik denk niet dat ik kan benadrukken hoe ernstig dit is.

Miljoenen klanten gebruiken zeker geïndexeerde weergaven, velen van hen hebben hun DML-code gemigreerd om MERGE te gebruiken , en een groot aantal daarvan zijn op Enterprise Edition (of gebruiken niet de NOEXPAND hint of verwijzen rechtstreeks naar de index). Paul wees er snel op dat NOEXPAND is niet vereist om het probleem in Enterprise Edition te reproduceren, en ontdekte ook veel van de andere details die nodig zijn om de bug te reproduceren.

Dit bericht is niet bedoeld om de donder van Jamie's of Paul's berichten te stelen; slechts een poging om de bezorgdheid te herhalen en het bewustzijn over deze kwestie te vergroten. Als u de gewoonte hebt om cumulatieve updates te negeren en ervoor kiest te wachten op servicepacks, en er is een kans dat dit probleem u op dit moment treft, dan bent u het aan uzelf, en niet aan uw belanghebbenden en klanten, verplicht om dit probleem serieus.

Dus wat moet je doen?

Welnu, wat u vervolgens doet, hangt af van welke versie en editie van SQL Server u gebruikt, en of de bug daadwerkelijk van invloed is (of zou kunnen zijn).

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

    Uw opties als u een van deze builds gebruikt:

    1. U moet updaten naar de laatste cumulatieve update voor uw filiaal:
      Branch Opgelost in CU Bouw Minimale build vereist
      om update toe te passen

      KB-artikel
      (Download)
      2008 Service Pack 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 Service Pack 1 CU #2 11.00.3339 11.00.3000 KB #2790947

      Tabel 1:Builds die de fix bevatten

    2. Als u de correctie niet toepast, moet u alle verwijzingen naar uw weergaven testen om te valideren dat ze in alle gevallen de juiste resultaten opleveren, ook nadat u de basistabellen hebt bijgewerkt met MERGE code> . Als dit niet het geval is (of als u vermoedt dat ze later worden beïnvloed), moet u de geclusterde index opnieuw opbouwen op alle betrokken views (of de geïndexeerde view(s) repareren met behulp van DBCC CHECKTABLE , zoals Paul in zijn bericht heeft beschreven), en stop met het gebruik van MERGE tegen deze tabellen totdat u de fix hebt toegepast. Als je MERGE blijft gebruiken tegen de basistabellen, bereid je voor om door te gaan met het repareren van de views om het probleem te voorkomen.
    3. Een snellere oplossing zou zijn om te voorkomen dat de beschadigde geïndexeerde weergave wordt gebruikt, door een van de volgende vereiste methoden te gebruiken:
      • pas de vraaghint toe OPTIE (UITBREID VIEWS) op alle relevante vragen;
      • verwijder expliciete verwijzingen naar de index in de weergave;
      • verwijder alle instanties van NOEXPAND in Standard of andere edities waar geïndexeerde weergaven niet automatisch worden vergeleken. .

      Maar dit zou natuurlijk grotendeels het doel van de geïndexeerde weergave tenietdoen - je kunt de index net zo goed laten vallen. Dat gezegd hebbende, is het meestal beter om langzaam de juiste resultaten te krijgen dan snel de verkeerde resultaten; dus misschien is dat oké.

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

    Helaas heb je een build die niet langer in de reguliere ondersteuning is, en het is onwaarschijnlijk dat dit probleem voor je wordt opgelost (tenzij je uitgebreide ondersteuning hebt en veel lawaai maakt). Dus je opties zijn hier beperkt - ga ofwel naar een ondersteunde tak volgens de bovenstaande tabel en pas de cumulatieve update toe, of kies een van de andere eerder genoemde opties.

    SQL Server 2000
    SQL Server 2005

    Het slechte nieuws is dat u ook een build gebruikt die niet langer wordt ondersteund. Het goede nieuws is dat het in dit specifieke geval niet uitmaakt - je kunt MERGE niet gebruiken hoe dan ook, dus deze bug heeft geen invloed op jou.

Andere MERGE-problemen

Helaas is dit verre van de eerste bug die we hebben gezien met MERGE , en het zal waarschijnlijk niet de laatste zijn. Hier is een snelle selectie van een dozijn MERGE bugs die nog steeds zijn gemarkeerd als actief op Connect:

  • #773895:MERGE meldt onjuist unieke sleutelovertredingen
  • #766165:MERGE evalueert gefilterde index per rij, niet na bewerking, wat een schending van de gefilterde index veroorzaakt
  • #723696:Basis MERGE upsert veroorzaakt deadlocks
  • #713699:Een systeembevestigingscontrole is mislukt ("cxrowset.cpp":1528)
  • #699055:MERGE-queryplannen staan ​​FK- en CHECK-beperkingsschendingen toe
  • #685800:Geparametriseerde DELETE en MERGE staan ​​schendingen van externe sleutelbeperkingen toe
  • #654746:samenvoegen in SQL2008 SP2 heeft nog steeds last van "Poging om de waarde van een niet-NULL-compatibele kolom in te stellen op NULL"
  • #635778:NOT MATCHED en MATCHED delen van een SQL MERGE-instructie zijn niet geoptimaliseerd
  • #633132:SAMENVOEGEN IN MET GEFILTERDE BRON werkt niet goed
  • #596086:MERGE-instructiefout bij gebruik van INSERT/DELETE en gefilterde index
  • #583719:MERGE-instructie behandelt niet-nulbare berekende kolommen onjuist in sommige scenario's
  • #539084:MERGE Stmt:zoekvoorwaarde op een niet-sleutelkolom en een ORDER BY in bron afgeleide tabel breekt MERGE volledig af

Nu kan het zijn dat sommige van deze bugs daadwerkelijk zijn verholpen, maar hun status is verkeerd omdat de lus terug naar Connect niet is gesloten. Zelfs als dat het geval is, kan het niet voor allemaal waar zijn (en mogelijk ook voor anderen die ik niet heb ontdekt).

Bovendien is door Dan Guzman aangetoond dat MERGE is niet immuun voor race-omstandigheden en andere gelijktijdigheidsproblemen. De oplossing is om HOLDLOCK . te gebruiken (of een hoger isolatieniveau); het is echter een veel voorkomende misvatting dat MERGE is volledig atomair en helemaal niet vatbaar voor dit probleem. Daarom vraag ik me hardop af:hoeveel MERGE verklaringen die er zijn, omvatten HOLDLOCK (of worden uitgevoerd onder SERIALIZABLE )? Hoeveel zijn er grondig getest op problemen met gelijktijdigheid?

Conclusie

Persoonlijk vind ik de syntaxis geweldig (hoewel ontmoedigend om te leren), maar elke keer dat er een probleem opduikt, erodeert het mijn vertrouwen in de uitvoerbaarheid van het vervangen van bestaande DML door de nieuwe constructie.

Met dat in gedachten, niet om Chicken Little te zijn, maar ik zou me niet op mijn gemak voelen om iemand aan te bevelen om MERGE te gebruiken. tenzij ze extreem uitgebreide tests uitvoeren. Sommige van deze problemen zijn ook aanwezig met standaard UPSERT methodieken, maar daar zijn de problemen duidelijker. MERGE , alleen al door zijn single-statement karakter, zorgt ervoor dat je in magie wilt geloven. Misschien zal het ooit resultaat opleveren, maar op dit moment weet ik dat het niet in staat zal zijn om een ​​persoon doormidden te zagen zonder serieuze hulp.


  1. Retourneer alle externe sleutels die verwijzen naar een bepaalde tabel in SQL Server

  2. Gegevenspartitionering voor grootschalige toepassingen

  3. Een experthandleiding voor Slony-replicatie voor PostgreSQL

  4. Meerdere query's uitgevoerd in Java in één instructie