Database
 sql >> база данни >  >> RDS >> Database

Ако използвате индексирани изгледи и MERGE, моля, прочетете това!

Колегата на MVP Джейми Томсън наскоро посочи, че има грешка с "грешни резултати" в SQL Server, която може да се прояви, когато са изпълнени следните условия:

  • Имате индексиран изглед, който свързва поне две таблици;
  • тези таблици са ограничени в двете посоки от външен ключ с една колона;
  • извършвате актуализации на основната(ите) таблица(и) с помощта на MERGE което включва и двете UPDATE и (DELETE или INSERT ) действия; и,
  • впоследствие издавате заявки, които препращат към индекса на изгледа (умишлено или не).

За съжаление статията в базата знания, описваща проблема (KB #2756471), е доста лека за подробности. Те не ви казват как да възпроизведете проблема или дори какво по-специално трябва да търсите, за да видите дали това ви засяга; и дори не споменават MERGE (което всъщност е ядрото на проблема, а не NOEXPAND , а не проста актуализация). Има някои допълнителни подробности в елемента Connect, които доведоха до корекцията; да се надяваме, че статията в KB ще бъде актуализирана с повече подробности скоро.

Междувременно резултатът, който може да видите, са неправилни данни – или по-добре казано, застояли данни :Заявката може да ви покаже старата версия на актуализирания(ите) ред(ове)! Прекарах няколко минути, опитвайки се да възпроизведа този сценарий в AdventureWorks, и се провалих мизерно. За щастие, Пол Уайт (блог | @SQL_Kiwi) написа изключителна публикация, описваща сценария и показваща пълна репродукция на проблема.

Не мисля, че мога да подчертая колко сериозно е това.

Със сигурност милиони клиенти използват индексирани изгледи, много от тях са мигрирали своя DML код, за да използват MERGE и голям брой от тях са в Enterprise Edition (или не са, но използват NOEXPAND намекват или препращат директно към индекса). Пол побърза да посочи, че NOEXPAND не се изисква за възпроизвеждане на проблема в Enterprise Edition, а също така откри много от другите подробности, необходими за възпроизвеждане на грешката.

Тази публикация не е предназначена да открадне гръмотевици от публикациите на Джейми или Пол; просто опит да се повтори загрижеността и да се повиши осведомеността по този въпрос. Ако имате навика да игнорирате кумулативни актуализации, избирайки да изчакате сервизни пакети, и има някакъв шанс този проблем да ви засегне в момента, вие го дължите на себе си, да не говорим за вашите заинтересовани страни и клиенти, да вземете този въпрос сериозно.

И какво трябва да направите?

Е, какво ще направите по-нататък зависи от това каква версия и издание на SQL Server използвате и дали грешката действително ви засяга (или може).

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

    Вашите опции, ако сте на една от тези компилации:

    1. Трябва да актуализирате до най-новата Кумулативна актуализация за вашия клон:
      Клон Коригирано в CU Изграждане Необходима е минимална компилация
      за прилагане на актуализация

      КБ Статия
      (Изтегляне)
      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

      Таблица 1 :Компилации, които съдържат корекцията

    2. Ако не приложите корекцията, тогава трябва да тествате всички препратки към вашите изгледи, за да потвърдите, че те връщат правилни резултати във всички случаи – включително след като сте актуализирали базовите таблици с помощта на MERGE код> . Ако не го направят (или подозирате, че по-късно може да бъдат засегнати), тогава трябва да изградите отново клъстерирания индекс на всички засегнати изгледи (или да поправите индексирания(и) изглед(и) с помощта на DBCC CHECKTABLE , както Пол описа в публикацията си), и спрете да използвате MERGE срещу тези таблици, докато не приложите корекцията. Ако продължите да използвате MERGE спрямо базовите таблици, подгответе се да продължите да поправяте изгледите, за да избегнете проблема.
    3. По-бързо решение би било да се предотврати използването на повреден индексиран изглед, като се използва някой от следните необходими методи:
      • приложете подсказката за заявката OPTION (EXPAND VIEWS) за всички релевантни запитвания;
      • премахнете всички изрични препратки към индекса в изгледа;
      • в стандартни или други издания, където индексираните изгледи не се съпоставят автоматично, премахнете всички екземпляри на 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 upsert, причиняващо застой
  • #713699 :Проверката за потвърждение на системата е неуспешна ("cxrowset.cpp":1528)
  • #699055 :плановете за заявки MERGE позволяват FK и CHECK нарушения на ограничения
  • #685800 :Параметризирано ИЗТРИВАНЕ и СЛИВАНЕ позволяват нарушения на ограниченията на външния ключ
  • #654746 :merge в SQL2008 SP2 все още страда от „Опит за задаване на стойност на колона без NULL на NULL“
  • #635778 :NOT MATCHED и MATCHED части от SQL MERGE израз не са оптимизирани
  • #633132 :СЛИВАНЕТО ВЪВ С ФИЛИРИРАН ИЗТОЧНИК не работи правилно
  • #596086 :Грешка в израза MERGE при използване на INSERT/DELETE и филтриран индекс
  • #583719 :Инструкцията MERGE третира неправилно изчислените колони без нула в някои сценарии
  • #539084 :MERGE Stmt :Условие за търсене в колона без ключ и ORDER BY в таблицата, извлечена от източника, нарушава MERGE напълно

Сега може да се окаже, че някои от тези грешки действително са отстранени, но състоянието им е неправилно, защото цикълът обратно към Connect не е затворен. Дори и случаят да е такъв, не може да е вярно за всички тях (и потенциално за други, които не съм разкрил).

В допълнение, Дан Гузман демонстрира, че MERGE не е имунизиран от условия на състезание и други проблеми с паралелността. Заобиколното решение е да използвате HOLDLOCK (или по-високо ниво на изолация); обаче е често срещано погрешно схващане, че MERGE е напълно атомен и изобщо не е предразположен към този проблем. Затова ще се чудя на глас:колко MERGE изявленията там включват HOLDLOCK (или се изпълняват под SERIALIZABLE )? Колко са били щателно тествани за проблеми, свързани с едновременността?

Заключение

Лично аз смятам, че синтаксисът е страхотен (макар и обезсърчителен за научаване), но всеки път, когато възникне проблем, това подкопава увереността ми в практичността на замяната на съществуващия DML с новата конструкция.

Имайки това предвид, да не бъда Chicken Little, но не бих се чувствал комфортно да препоръчвам на някой да използва MERGE освен ако не прилагат изключително изчерпателно тестване. Някои от тези проблеми присъстват и при стандартния UPSERT методологии, но там проблемите са по-очевидни. MERGE , само чрез своята същност на едно изявление, ви кара да искате да повярвате в магията. Може би някой ден ще се справи, но точно сега знам, че няма да може да разсече човек наполовина без сериозна помощ.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Автоматизирано тестване на настолното приложение:преглед на целесъобразността и рамки

  2. Използване на strace като DG40DBC инструмент за отстраняване на грешки в Linux

  3. Минимално регистриране с INSERT...SELECT в Heap Tables

  4. Съвети за заключвания за четене/запис в зависимост от нивото на изолация на транзакциите в MSSQL

  5. Създаване на тестова среда от производствено хранилище