sql >> Databáze >  >> RDS >> Database

Pokud používáte indexovaná zobrazení a SLOUČENÍ, přečtěte si toto!

Kolega MVP Jamie Thomson nedávno poukázal na to, že na serveru SQL Server je chyba „nesprávných výsledků“, která se může projevit, když jsou splněny následující podmínky:

  • Máte indexované zobrazení, které spojuje alespoň dvě tabulky;
  • tyto tabulky jsou omezeny v obou směrech cizím klíčem s jedním sloupcem;
  • aktualizace základních tabulek provádíte pomocí MERGE který zahrnuje jak UPDATE a (DELETE nebo INSERT ) akce; a
  • následně zadáte dotazy, které odkazují na index v zobrazení (záměrně nebo ne).

Bohužel článek znalostní báze popisující problém (KB č. 2756471) je v podrobnostech poměrně stručný. Neřeknou vám, jak problém reprodukovat, nebo dokonce ani to, co konkrétně byste měli hledat, abyste zjistili, zda se vás to týká; a ani se nezmiňují o MERGE (což je ve skutečnosti jádro problému, nikoli NOEXPAND a nejde o jednoduchou aktualizaci). V položce Connect jsou některé další podrobnosti, které přinesly opravu; doufám, že článek KB bude brzy aktualizován o další podrobnosti.

Mezitím mohou být výsledkem nesprávná data – nebo lépe řečeno zastaralá data :Dotaz vám může zobrazit starou verzi aktualizovaného řádku (řádků)! Strávil jsem několik minut pokusem o reprodukování tohoto scénáře v AdventureWorks a velmi selhal. Naštěstí Paul White (blog | @SQL_Kiwi) napsal vynikající příspěvek popisující scénář a ukazující úplné opakování problému.

Nemyslím si, že mohu zdůraznit, jak vážné to je.

Miliony zákazníků jistě používají indexovaná zobrazení, mnozí z nich migrovali svůj kód DML na MERGE a velký počet z nich je na Enterprise Edition (nebo nejsou, ale používají NOEXPAND nápověda nebo přímo odkazují na index). Paul rychle poukázal na to, že NOEXPAND není vyžadována k reprodukci problému v Enterprise Edition a také objevil mnoho dalších podrobností potřebných k reprodukci chyby.

Účelem tohoto příspěvku není ukrást jakýkoli hrom z příspěvků Jamieho nebo Paula; jen pokus zopakovat obavy a zvýšit povědomí o tomto problému. Pokud máte ve zvyku ignorovat kumulativní aktualizace, rozhodnete se čekat na aktualizace Service Pack a existuje nějaká šance, že by se vás tento problém mohl týkat právě teď, dlužíte sami sobě, nemluvě o vašich akcionářích a zákaznících, abyste tento problém vážně.

Co byste tedy měli dělat?

Co uděláte dále, závisí na tom, jakou verzi a edici SQL Serveru používáte, a zda se vás chyba skutečně týká (nebo by mohla).

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

    Vaše možnosti, pokud používáte jednu z těchto sestav:

    1. Měli byste aktualizovat na nejnovější kumulativní aktualizaci pro vaši pobočku:
      Pobočka Opraveno v CU Sestavit Požaduje se minimální sestavení
      k použití aktualizace

      Článek KB
      (Stáhnout)
      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

      Tabulka 1:Sestavení obsahující opravu

    2. Pokud opravu nepoužijete, musíte otestovat všechny odkazy na vaše zobrazení, abyste ověřili, že ve všech případech vracejí správné výsledky – i poté, co jste aktualizovali základní tabulky pomocí MERGE kód> . Pokud tomu tak není (nebo máte podezření, že by mohly být později ovlivněny), měli byste znovu sestavit seskupený index na všech dotčených pohledech (nebo opravit indexované pohledy pomocí DBCC CHECKTABLE , jak Paul popsal ve svém příspěvku), a přestaňte používat MERGE proti těmto tabulkám, dokud nepoužijete opravu. Pokud budete pokračovat v používání MERGE v porovnání se základními tabulkami se připravte na pokračování opravy pohledů, abyste se vyhnuli problému.
    3. Rychlejší opravou by bylo zabránit tomu, aby se poškozený indexovaný pohled vůbec používal, a to pomocí kterékoli z následujících požadovaných metod:
      • použijte nápovědu k dotazu OPTION (EXPAND VIEWS) na všechny relevantní dotazy;
      • odstraňte ze zobrazení veškeré explicitní odkazy na index;
      • ve standardních nebo jiných edicích, kde se indexovaná zobrazení automaticky neshodují, odeberte všechny výskyty NOEXPAND .

      Ale to by samozřejmě do značné míry zmařilo účel indexovaného pohledu – může to také jednoduše index vypustit. To znamená, že je obvykle lepší získat správné výsledky pomalu, než rychle získat špatné výsledky; takže možná je to v pořádku.

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

    Bohužel jste na sestavení, které již není v běžné podpoře, a je nepravděpodobné, že tento problém bude vyřešen za vás (pokud nemáte rozšířenou podporu a neděláte spoustu hluku). Vaše možnosti jsou zde tedy omezené – buď se přesuňte do podporované větve podle výše uvedené tabulky a použijte kumulativní aktualizaci, nebo zvolte jednu z dalších možností uvedených výše.

    SQL Server 2000
    SQL Server 2005

    Špatná zpráva je, že jste také na sestavení, které již není podporováno. Dobrou zprávou je, že v tomto konkrétním případě na tom nezáleží – nemůžete použít MERGE každopádně vás tato chyba nemůže ovlivnit.

Další problémy MERGE

Bohužel to není zdaleka první chyba, kterou jsme viděli u MERGE a pravděpodobně nebude poslední. Zde je rychlý výběr z tuctu MERGE chyby, které jsou na Connectu stále označeny jako aktivní:

  • #773895 :SLOUČENÍ nesprávně hlásí jedinečná porušení klíčových slov
  • #766165 :MERGE vyhodnocuje filtrovaný index na řádek, nikoli po operaci, což způsobuje porušení filtrovaného indexu
  • #723696:Základní MERGE upsert způsobující uváznutí
  • #713699 :Kontrola systémového tvrzení selhala ("cxrowset.cpp":1528)
  • #699055 :Plány dotazů MERGE umožňují porušení omezení FK a CHECK
  • #685800 :Parametrizované DELETE a MERGE umožňují porušení omezení cizího klíče
  • #654746 :sloučení v SQL2008 SP2 stále trpí "Pokusem nastavit hodnotu sloupce, který nemá hodnotu NULL" na NULL"
  • #635778 :Části NOT MATCHED a MATCHED příkazu SQL MERGE nejsou optimalizovány
  • #633132 :SLOUČENÍ DO S FILTROVANÝM ZDROJEM nefunguje správně
  • #596086 :Chyba příkazu MERGE při použití a filtrování indexu INSERT/DELETE
  • #583719 :Příkaz MERGE v některých scénářích nesprávně zachází s vypočítanými sloupci bez možnosti null
  • #539084 :MERGE Stmt :Podmínka vyhledávání v neklíčovém sloupci a ORDER BY ve zdrojové odvozené tabulce zcela přeruší MERGE

Nyní se může stát, že některé z těchto chyb byly skutečně opraveny, ale jejich stav je nesprávný, protože smyčka zpět do Connect nebyla uzavřena. I kdyby tomu tak bylo, nemůže to být pravda pro všechny (a potenciálně pro další, které jsem neodhalil).

Dan Guzman navíc prokázal, že MERGE není imunní vůči rasovým podmínkám a dalším problémům souběžnosti. Řešením je použití HOLDLOCK (nebo vyšší úroveň izolace); nicméně, to je obyčejná mylná představa, že MERGE je zcela atomový a není k tomuto problému vůbec náchylný. Proto se nahlas ptám:kolik MERGE příkazy tam zahrnují HOLDLOCK (nebo jsou spouštěny pod SERIALIZABLE )? Kolik z nich bylo důkladně testováno na problémy související se souběžností?

Závěr

Osobně si myslím, že syntaxe je skvělá (ačkoli skličující se naučit), ale pokaždé, když se objeví nějaký problém, nahlodá mou důvěru v praktičnost nahrazení stávajícího DML novým konstruktem.

S ohledem na to nebýt Chicken Little, ale necítil bych se pohodlně doporučovat komukoli, aby používal MERGE pokud nezavedou extrémně komplexní testování. Některé z těchto problémů se vyskytují také u standardního UPSERT metodiky, ale tam jsou problémy zjevnější. MERGE , pouze díky své povaze s jedním výrokem vás nutí věřit v magii. Možná to jednoho dne přinese, ale právě teď vím, že bez seriózní pomoci nebude schopné rozpůlit člověka.


  1. Jak funguje indexování

  2. Jak použít SqlCommand k VYTVOŘENÍ DATABÁZE s parametrizovaným názvem db?

  3. Seřadit posledních N řádků v databázi?

  4. Použití aliasu ve výpočtech SQL