Database
 sql >> Baza danych >  >> RDS >> Database

Jeśli używasz widoków indeksowanych i MERGE, przeczytaj to!

Kolega MVP, Jamie Thomson, zwrócił niedawno uwagę na błąd „niewłaściwych wyników” w SQL Server, który może objawiać się, gdy spełnione są następujące warunki:

  • Masz zindeksowany widok, który łączy co najmniej dwie tabele;
  • te tabele są ograniczone w obu kierunkach przez jednokolumnowy klucz obcy;
  • wykonujesz aktualizacje tabel podstawowych za pomocą MERGE który zawiera zarówno AKTUALIZACJA i (USUŃ lub WSTAW ) działania; i,
  • następnie wysyłasz zapytania, które odwołują się do indeksu w widoku (celowo lub nie).

Niestety, artykuł z bazy wiedzy opisujący problem (KB #2756471) zawiera dość mało szczegółów. Nie mówią ci, jak odtworzyć problem, ani nawet czego konkretnie powinieneś szukać, aby zobaczyć, czy dotyczy to ciebie; i nawet nie wspominają o MERGE (co jest właściwie sednem problemu, a nie NOEXPAND , a nie zwykłą aktualizację). Istnieje kilka dodatkowych szczegółów w elemencie Connect, które spowodowały poprawkę; miejmy nadzieję, że artykuł KB zostanie wkrótce zaktualizowany o więcej szczegółów.

W międzyczasie wynik, który możesz zobaczyć, to nieprawidłowe dane – lub lepiej, nieaktualne dane :zapytanie może pokazać starą wersję zaktualizowanych wierszy! Poświęciłem kilka minut na odtworzenie tego scenariusza w AdventureWorks, ale poniosłem sromotną porażkę. Na szczęście Paul White (blog | @SQL_Kiwi) napisał znakomity post opisujący scenariusz i pokazujący pełną kopię problemu.

Nie sądzę, abym mógł podkreślić, jak poważne to jest.

Z pewnością miliony klientów korzystają z widoków indeksowanych, wielu z nich przeniosło swój kod DML do MERGE , a duża ich liczba jest w wersji Enterprise (lub nie, ale używa NOEXPAND wskazówka lub bezpośrednio odwołują się do indeksu). Paul szybko zauważył, że NOEXPAND nie jest wymagane do odtworzenia problemu w wersji Enterprise, a także odkrył wiele innych szczegółów wymaganych do odtworzenia błędu.

Ten post nie ma na celu kradzieży grzmotów z postów Jamiego lub Paula; to tylko próba ponownego wyrażenia obaw i podniesienia świadomości na ten temat. Jeśli masz zwyczaj ignorowania Aktualizacji zbiorczych, decydując się na czekanie na dodatki Service Pack i jest jakakolwiek szansa, że ​​ten problem może Cię teraz dotyczyć, jesteś to winien sobie, nie wspominając o swoich interesariuszach i klientach, aby podjąć ten problem poważnie.

Więc co powinieneś zrobić?

Cóż, to, co zrobisz dalej, zależy od używanej wersji i edycji SQL Server oraz od tego, czy błąd faktycznie dotyczy Ciebie (lub może).

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

    Twoje opcje, jeśli korzystasz z jednej z tych kompilacji:

    1. Powinieneś zaktualizować do najnowszej aktualizacji zbiorczej dla swojego oddziału:
      Oddział Naprawiono w CU Buduj Wymagana minimalna kompilacja
      do zastosowania aktualizacji

      Artykuł KB
      (Pobierz)
      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.000.4000 KB #2777358
      2012 RTM CU #5 11.00.2395 11.000.2100 KB #2777772
      2012 Service Pack 1 CU #2 11.00.3339 11.00.3000 KB #2790947

      Tabela 1:Kompilacje zawierające poprawkę

    2. Jeśli nie zastosujesz poprawki, musisz przetestować wszystkie odwołania do swoich widoków, aby sprawdzić, czy zwracają one poprawne wyniki we wszystkich przypadkach — w tym po zaktualizowaniu tabel podstawowych za pomocą MERGE . Jeśli tak się nie stanie (lub podejrzewasz, że może to mieć później wpływ), powinieneś odbudować indeks klastrowy we wszystkich widokach, których to dotyczy (lub naprawić zindeksowane widoki za pomocą DBCC CHECKTABLE , jak opisał Paul w swoim poście) i przestań używać MERGE w tych tabelach, dopóki nie zastosujesz poprawki. Jeśli nadal będziesz używać MERGE w stosunku do tabel podstawowych, przygotuj się do dalszej naprawy widoków, aby uniknąć problemu.
    3. Szybszym rozwiązaniem byłoby uniemożliwienie używania uszkodzonego indeksowanego widoku w ogóle, przy użyciu dowolnej z następujących wymaganych metod:
      • zastosuj wskazówkę dotyczącą zapytania OPCJA (ROZSZERZ WIDOKI) do wszystkich odpowiednich zapytań;
      • usuń wszelkie wyraźne odniesienia do indeksu w widoku;
      • w wersjach Standard lub innych, w których zindeksowane widoki nie są dopasowywane automatycznie, usuń wszystkie wystąpienia NOEXPAND .

      Ale to oczywiście w dużej mierze pokonałoby cel indeksowanego widoku – równie dobrze może po prostu obniżyć indeks. To powiedziawszy, zwykle lepiej jest powoli uzyskiwać właściwe wyniki niż szybko uzyskiwać złe wyniki; więc może to w porządku.

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

    Niestety, korzystasz z wersji, która nie jest już objęta głównym wsparciem i jest mało prawdopodobne, że ten problem zostanie rozwiązany za Ciebie (chyba że korzystasz z rozszerzonego wsparcia i robisz dużo hałasu). Więc twoje opcje są tutaj ograniczone – albo przejdź do obsługiwanej gałęzi zgodnie z powyższą tabelą i zastosuj aktualizację zbiorczą lub wybierz jedną z innych opcji wspomnianych wcześniej.

    SQL Server 2000
    SQL Server 2005

    Cóż, zła wiadomość jest taka, że ​​korzystasz z wersji, która nie jest już obsługiwana. Dobrą wiadomością jest to, że w tym konkretnym przypadku nie ma to znaczenia – nie możesz użyć MERGE w każdym razie, więc ten błąd nie może Cię dotyczyć.

Inne problemy z MERGE

Niestety jest to dalekie od pierwszego błędu, który widzieliśmy w MERGE i prawdopodobnie nie będzie to ostatnie. Oto szybki wybór tuzinu MERGE błędy, które są nadal oznaczone jako aktywne w Connect:

  • #773895:MERGE nieprawidłowo zgłasza unikalne naruszenia kluczy
  • #766165:MERGE ocenia filtrowany indeks na wiersz, a nie po operacji, co powoduje naruszenie filtrowanego indeksu
  • #723696:Podstawowe upsert MERGE powodujące zakleszczenia
  • #713699:Sprawdzanie asercji systemu nie powiodło się ("cxrowset.cpp":1528)
  • #699055:plany zapytań MERGE umożliwiają naruszenia ograniczeń FK i CHECK
  • #685800:Sparametryzowane DELETE i MERGE pozwalają na naruszenie ograniczeń klucza obcego
  • #654746:scalanie w SQL2008 SP2 nadal cierpi z powodu „Próby ustawienia wartości kolumny nieobsługującej NULL na NULL”
  • #635778:Części NOT MATCHED i MATCHED instrukcji SQL MERGE nie są zoptymalizowane
  • #633132:Scalanie z filtrowanym źródłem nie działa prawidłowo
  • #596086:Błąd instrukcji MERGE, gdy użyto INSERT/DELETE i przefiltrowano indeks
  • #583719:instrukcja MERGE niepoprawnie traktuje kolumny obliczeniowe niepodlegające wartości null w niektórych scenariuszach
  • #539084:MERGE Stmt:Warunek wyszukiwania w kolumnie bez klucza i ORDER BY w tabeli źródłowej przerywa MERGE całkowicie

Teraz może się zdarzyć, że niektóre z tych błędów zostały rzeczywiście naprawione, ale ich stan jest zły, ponieważ pętla z powrotem do Connect nie została zamknięta. Nawet jeśli tak jest, nie może to dotyczyć wszystkich z nich (i potencjalnie innych, których nie odkryłem).

Ponadto Dan Guzman zademonstrował, że MERGE nie jest odporny na warunki rasowe i inne problemy ze współbieżnością. Rozwiązaniem jest użycie HOLDLOCK (lub wyższy poziom izolacji); jednak powszechnym błędem jest to, że MERGE jest całkowicie atomowa i w ogóle nie jest podatna na ten problem. Dlatego będę się głośno zastanawiać:ile MERGE dostępne tam instrukcje obejmują HOLDLOCK (lub są wykonywane pod SERIALIZABLE )? Ile zostało dokładnie przetestowanych pod kątem problemów związanych ze współbieżnością?

Wniosek

Osobiście uważam, że składnia jest świetna (choć zniechęcająca do nauki), ale za każdym razem, gdy pojawia się problem, podważa to moje zaufanie do praktyczności zastąpienia istniejącego DML nową konstrukcją.

Mając to na uwadze, nie chcę być Kurczakiem Małym, ale nie czułbym się komfortowo polecając komukolwiek użycie MERGE chyba że wdrożą niezwykle wszechstronne testy. Niektóre z tych problemów występują również w standardowym UPSERT metodologii, ale tam problemy są bardziej oczywiste. MERGE , tylko dzięki swojej jednoznacznej naturze sprawia, że ​​chcesz uwierzyć w magię. Może kiedyś to się uda, ale teraz wiem, że bez poważnej pomocy nie da się przeciąć człowieka na pół.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Operator SQL mniejszy lub równy (=) dla początkujących

  2. Grupowanie z opisem przypadku

  3. Jak utworzyć dokument Excel z programu Java za pomocą Apache POI

  4. Upuść vs Obcinaj w SQL

  5. Instrukcja SQL SELECT INTO