Czy NOLOCK (wskazówka serwera Sql) jest złą praktyką?

125

Zajmuję się tworzeniem witryn internetowych i aplikacji, które nie są krytyczne -> np. oprogramowanie bankowe, lot kosmiczny, aplikacja do monitorowania intensywnej terapii, itp. Masz pomysł.

Tak więc, przy tym ogromnym zastrzeżeniu, czy używanie wskazówki NOLOCK w jakimś oświadczeniu Sql jest złe? Kilka lat temu inny administrator Sql zasugerował, że powinienem używać NOLOCK, jeśli jestem zadowolony z „brudnego odczytu”, który da mi nieco większą wydajność poza moim systemem, ponieważ każdy odczyt nie blokuje tabela / wiersz / cokolwiek.

Powiedziano mi również, że to świetne rozwiązanie, jeśli mam martwe zamki. Więc zacząłem podążać za tą myślą przez kilka lat, aż guru Sql pomógł mi z jakimś przypadkowym kodem i zauważył wszystkie NOLOCKS w moim kodzie sql. Zostałem grzecznie zbesztany, a on próbował mi to wyjaśnić (dlaczego to nie jest dobre) i trochę się zgubiłem. Czułem, że esencją jego wyjaśnienia było „to bandażowe rozwiązanie poważniejszego problemu… zwłaszcza jeśli doświadczasz impasu. W związku z tym napraw źródło problemu ”.

Ostatnio trochę googlowałem na ten temat i trafiłem na ten post .

Więc, czy jakiś sql db guru sensei może mnie oświecić?

Pure.Krome
źródło
Nie rozumiem Sam, mówisz, że użyj izolacji Snapshot, jeśli jest to strona internetowa z dużą ilością czytania. Ale wtedy mówisz, że TAK to zrobiłeś i jest źle? czy po prostu używają NOLOCK?
Pure.Krome

Odpowiedzi:

67

Ze wskazówką NOLOCK poziom izolacji transakcji dla SELECTinstrukcji wynosi READ UNCOMMITTED. Oznacza to, że zapytanie może zobaczyć brudne i niespójne dane.

Z reguły nie jest to dobry pomysł. Nawet jeśli to brudne zachowanie odczytu jest w porządku dla Twojej krytycznej aplikacji sieciowej, skanowanie NOLOCK może spowodować błąd 601, który zakończy zapytanie z powodu przenoszenia danych w wyniku braku ochrony blokującej.

Proponuję przeczytać książkę When Snapshot Isolation Helps and When It Boli - w większości przypadków MSDN zaleca użycie READ COMMITTED SNAPSHOT zamiast SNAPSHOT.

Kucyki OMG
źródło
1
Rex, prosimy o dodanie notatki o izolacji migawki.
Sam Saffron
2
Tak, Sam mówi o izolacji migawki, a ty sugerujesz przeczytanie zatwierdzonej migawki. jestem taki zdezorientowany: P (i jeszcze nie zagłębiłem się w artykuły!)
Pure.Krome
2
Czasami jest przydatny, ale zwykle nie do produkcji. Używam go często do wyciągania próbki danych do testowania lub do generowania raportów, gdzie głównie zależy mi na przybliżonym rzędzie wielkości, gdzie brudny odczyt nie ma znaczenia.
TimothyAWiseman
NOLOCK == Nie obchodzi mnie, czy brakuje zatwierdzonych wierszy, dołączane są niezatwierdzone wiersze, w rzadkich przypadkach ten sam wiersz jest zwracany więcej niż raz, aw bardzo rzadkich przypadkach zwracane są wiersze, które nie pasują do mojego zapytania. (patrz blogs.msdn.com/b/sqlcat/archive/2007/02/01/… , znalezione w innym zgłoszeniu SO na ten temat)
Andrew Hill
106

Przed rozpoczęciem pracy na przepełnienie stosu, byłem przeciwko NOLOCKna zasadzie, że potencjalnie można wykonać SELECTz NOLOCKi wrócić wyniki z danych, które mogą być nieaktualne lub niezgodne. Należy przemyśleć, ile rekordów można wstawiać / aktualizować w tym samym czasie, gdy inny proces może wybierać dane z tej samej tabeli. Jeśli zdarza się to często, istnieje duże prawdopodobieństwo zakleszczenia, chyba że używasz trybu bazy danych, takiego jak READ COMMITED SNAPSHOT.

Od tego czasu zmieniłem swoje NOLOCKpodejście do korzystania z programu po obejrzeniu, jak może poprawić SELECTwydajność, a także wyeliminować zakleszczenia na masowo ładowanym serwerze SQL. Czasami możesz nie przejmować się tym, że Twoje dane nie są dokładnie w 100% zatwierdzone i potrzebujesz szybko z powrotem uzyskać wyniki, nawet jeśli mogą być nieaktualne.

Zadaj sobie pytanie, myśląc o użyciu NOLOCK:

Czy moje zapytanie zawiera tabelę, która ma dużą liczbę poleceń INSERT/ UPDATEi czy obchodzi mnie, czy w danych zwróconych z zapytania może brakować tych zmian w danym momencie?

Jeśli odpowiedź brzmi nie, użyj, NOLOCKaby poprawić wydajność.


Właśnie przeprowadziłem szybkie wyszukiwanie NOLOCKsłowa kluczowego w bazie kodu dla przepełnienia stosu i znalazłem 138 wystąpień, więc używamy go w wielu miejscach.

Geoff Dalgas
źródło
7
IMO, to jest trochę uproszczone. Zakleszczenia można usunąć za pomocą indeksów pokrywających, odciążając indeks klastrowy.
Mitch Wheat
8
Nie chcę umniejszać znaczenia dobrego pokrycia indeksu. Czasami zapytania korzystające z NOLOCK mogą zwiększyć wydajność oprócz zysków uzyskiwanych przez indeksy w tabelach z dużą liczbą wstawień / aktualizacji. Szybkość zapytań w przypadku przepełnienia stosu ma ogromne znaczenie, nawet kosztem niedokładnych lub brakujących danych.
Geoff Dalgas
9
Najwyraźniej można uzyskać zduplikowane wiersze za pomocą NOLOCK. Oznacza to, że muszę zlekceważyć twoją odpowiedź. Przepraszam.
ErikE,
1
@MitchWheat A SELECT, odczytując tylko z indeksu pokrywającego, może spowodować zakleszczenie. SPID 1) zaczyna się SELECTod indeksu pokrywającego. SPID 2) Uruchom UPDATEtabelę. Aktualizacja przechodzi następnie do aktualizacji indeksu pokrycia. UPDATEosiąga zakres indeksu zablokowany przez SELECTi zostaje zablokowany. SPID 1) nadal przeszukuje indeks pokrywający, znajduje zakres zablokowany przez UPDATEi zostaje zablokowany. DEADLOCK . Nic nie może rozwiązać tego impasu (z wyjątkiem przechwytywania błędu SQL Server 1205 i automatycznego ponawiania lub używania NOLOCK)
Ian Boyd
2
Myślę, że ważne jest, aby zwrócić uwagę na tę odpowiedź, że była ona odpowiednia dla danego problemu . W zależności od aplikacji, ryzyko nieaktualnych / niezatwierdzonych / zduplikowanych / brakujących danych może nie być warte kompromisu.
Holistic Developer
20

Jeśli nie przejmujesz się brudnymi odczytami (np. W sytuacji przeważnie READ), to NOLOCKjest w porządku.

ALE należy pamiętać, że większość problemów z blokowaniem wynika z braku „poprawnych” indeksów dla obciążenia zapytaniami (zakładając, że sprzęt jest odpowiedni do zadania).

A wyjaśnienie guru było poprawne. Zwykle jest to bandażowe rozwiązanie poważniejszego problemu.

Edycja : zdecydowanie nie sugeruję, aby używać NOLOCK. Chyba powinienem był to jasno wyrazić. (Używałbym go tylko w ekstremalnych okolicznościach, w których przeanalizowałem, że jest OK). Jako przykład, jakiś czas temu pracowałem nad TSQL, który został spryskany NOLOCKem, aby spróbować złagodzić problemy z blokowaniem. Usunąłem je wszystkie, zaimplementowałem prawidłowe indeksy i WSZYSTKIE zakleszczenia zniknęły.

Mitch Wheat
źródło
3
Hmm ... nadal tego nie rozumiem. Więc jest w porządku, ale to też kiepska forma… czy to właśnie mówisz?
Pure.Krome,
Zakładając, że NIGDY nie przejmujesz się brudnymi odczytami, to nie zaszkodzi. ALE jest to zwykle przypadek leczenia objawu, a nie przyczyny ...
Mitch Wheat
2
Cóż, nie sądzę, że jego sprawiedliwy rexem został po prostu odrzucony, myślę, że nie rozwiązałeś arbitralnych błędów, które po prostu pojawiają się, gdy używasz nolock. Nie jest dobrze, gdy raz na jakiś czas pojawia się pusta strona błędu w witrynie, to naprawdę kiepska forma. Nie podoba mi się stwierdzenie, że „jeśli nie przejmujesz się brudnymi czytaniami, to jest w porządku” ... nie jest w porządku, nawet jeśli nie obchodzą cię brudne teksty
Sam Saffron
Pusta strona, która pojawia się, gdy zapytanie generuje wyjątek, dla którego nie zaimplementowano logiki ponawiania. Co dzieje się w twoich witrynach, gdy wyniki wykonywania zapytań są wyjątkiem, czy wszędzie masz logikę ponawiania?
Sam Saffron
Weź bardzo dobrze zoptymalizowane zapytanie, o którym wiesz, że trafia we właściwe indeksy. Następnie dodaj wskazówki nolock i zobacz, jak działa szybciej. Jeśli nie przejmujesz się brudnymi odczytami, nigdy nie zrobisz sobie krzywdy używając nolocka.
Hardwareguy
13

Wątpię, czy był to „guru”, który miał jakiekolwiek doświadczenie w dużym ruchu ...

Witryny internetowe są zwykle „brudne” do czasu, gdy osoba przegląda całkowicie załadowaną stronę. Rozważ formularz, który ładuje się z bazy danych, a następnie zapisuje edytowane dane? To idiotyczne, jak ludzie mówią, że brudne książki są takie nie, nie.

To powiedziawszy, jeśli masz wiele warstw tworzonych na wybranych elementach, możesz tworzyć niebezpieczną nadmiarowość. Jeśli masz do czynienia ze scenariuszami dotyczącymi pieniędzy lub statusu, potrzebujesz nie tylko odczytu / zapisu danych transakcyjnych, ale także odpowiedniego rozwiązania współbieżnego (coś, czym większość „guru” nie zawraca sobie głowy).

Z drugiej strony, jeśli masz zaawansowane wyszukiwanie produktów dla witryny internetowej (tj. Coś, co prawdopodobnie nie będzie buforowane i będzie trochę intensywne) i kiedykolwiek zbudowałeś witrynę z więcej niż kilkoma równoczesnymi użytkownikami (zjawisko to, ilu „eksperci” tego nie zrobili), niedorzeczne jest butelkowanie wszystkich innych procesów, które za tym stoją.

Dowiedz się, co to znaczy i używaj go w odpowiednich przypadkach. W dzisiejszych czasach Twoja baza danych prawie zawsze będzie Twoją główną szyjką, a rozsądne korzystanie z NOLOCK może zaoszczędzić tysiące na infrastrukturze.

EDYCJA: Pomaga nie tylko w zakleszczeniach, ale także na tym, jak bardzo wszyscy inni będą czekać, aż skończysz, lub odwrotnie.

Używasz NOLOCK Hint w EF4?

Gats
źródło
10

Żadna z odpowiedzi nie jest błędna, choć może trochę zagmatwana.

  • Podczas wykonywania zapytań dotyczących pojedynczych wartości / wierszy zawsze jest złą praktyką używanie NOLOCK - prawdopodobnie nigdy nie chcesz wyświetlać nieprawidłowych informacji, a może nawet podejmować żadnych działań na niepoprawnych danych.
  • Podczas wyświetlania zgrubnych informacji statystycznych NOLOCK może być bardzo przydatny. Weźmy SO jako przykład: nonsensem byłoby branie zamków w celu odczytania dokładnej liczby wyświetleń pytania lub dokładnej liczby pytań dla tagu. Nikogo to nie obchodzi, jeśli teraz nieprawidłowo podasz 3360 pytań z tagiem „sql-server”, a z powodu wycofania transakcji, 3359 pytań sekundę później.
realMarkusSchmidt
źródło
W ogóle nie zgadzam się z twoim pierwszym punktem. JEŚLI odpytujesz pojedyncze wartości / wiersze i określasz unikatowy identyfikator dla tego wiersza i wiesz, że żaden inny proces nie będzie miał do niego dostępu, wówczas użycie nolock jest całkowicie dopuszczalne i zmniejsza blokowanie w aplikacji współbieżnej.
tuseau
1
Nie, nie jest. Wiersz może się zmienić z innych powodów, na przykład wstawienie innego wiersza powoduje podzielenie strony. Prawidłowe indeksowanie, odczyt zatwierdzonej migawki i izolacja migawki to prawie zawsze lepsze pomysły.
Mark Sowul
1
@tuseau jeśli „wiesz”, że żaden inny proces nie będzie miał dostępu do wiersza, czynność zablokowania niczego nie zablokuje, więc (praktycznie) nic Cię nie kosztuje,
Andrew Hill
2

Jako profesjonalny programista powiedziałbym, że to zależy. Ale zdecydowanie postępuję zgodnie z radami GATS i OMG Kucy. Wiedz, co robisz, wiedz, kiedy to pomaga, a kiedy boli i

przeczytaj wskazówki i inne kiepskie pomysły

co może sprawić, że głębiej zrozumiesz działanie serwera sql. Generalnie kieruję się zasadą, że podpowiedzi SQL są ZŁE, ale niestety używam ich od czasu do czasu, gdy mam dość zmuszania serwera SQL do robienia pewnych rzeczy ... Ale to są rzadkie przypadki.

Łukasz

Lucky Luke
źródło
2

Kiedy obsługa aplikacji chciała odpowiedzieć na zapytania ad-hock z serwera produkcyjnego przy użyciu SSMS (które nie były obsługiwane przez raportowanie), poprosiłem, aby użyli nolock. W ten sposób nie ma to wpływu na „główną” działalność.

richard101
źródło
2

Zgadzam się z niektórymi uwagami na temat podpowiedzi NOLOCK, a zwłaszcza z tymi, które mówią „używaj jej, kiedy jest to właściwe”. Jeśli aplikacja jest źle napisana i używa współbieżności w niewłaściwy sposób - może to spowodować eskalację blokady. Stoły wysoce transakcyjne również są cały czas blokowane ze względu na ich charakter. Posiadanie dobrego pokrycia indeksu nie pomoże w pobieraniu danych, ale ustawienie POZIOMU ​​IZOLACJI na ODCZYTAJ NIEZGODNE - tak. Uważam również, że używanie podpowiedzi NOLOCK jest bezpieczne w wielu przypadkach, gdy charakter zmian jest przewidywalny. Na przykład - w produkcji, gdy zadania z podróżnikami przechodzą przez różne procesy z dużą ilością wstawek pomiarów, możesz bezpiecznie wykonać zapytanie o ukończone zadanie za pomocą wskazówki NOLOCK i w ten sposób uniknąć kolizji z innymi sesjami, które stawiają PROMOTOWANE lub WYŁĄCZNE blokady na stole /strona. Dane, do których uzyskujesz dostęp w tym przypadku, są statyczne, ale mogą znajdować się w bardzo transakcyjnej tabeli z setkami milionów rekordów i tysiącami aktualizacji / wstawień na minutę. Twoje zdrowie

user2041151
źródło
2

Uważam, że używanie nolocka praktycznie nigdy nie jest poprawne.

Jeśli czytasz pojedynczy wiersz, prawidłowy indeks oznacza, że ​​nie będziesz potrzebować NOLOCK, ponieważ działania w poszczególnych wierszach są wykonywane szybko.

Jeśli czytasz wiele wierszy dla czegoś innego niż tymczasowe wyświetlanie i zależy Ci na możliwości powtórzenia wyniku lub obrony za pomocą wygenerowanej liczby, to NOLOCK nie jest odpowiedni.

NOLOCK jest zastępczym znacznikiem dla „Nie obchodzi mnie, czy ta odpowiedź zawiera zduplikowane wiersze, wiersze, które zostały usunięte lub wiersze, które nigdy nie zostały wstawione na początku z powodu wycofania”

Błędy, które są możliwe w NOLOCK:

  • Wiersze pasujące w ogóle nie są zwracane.
  • pojedyncze wiersze są zwracane wiele razy (w tym wiele wystąpień tego samego klucza podstawowego)
  • Wiersze, które nie pasują, są zwracane.

Każda czynność, która może spowodować podział strony podczas działania funkcji noLock select, może spowodować takie zdarzenia. Prawie każda czynność (nawet usunięcie) może spowodować podział strony.

Dlatego: jeśli „wiesz”, że wiersz nie zostanie zmieniony podczas działania, nie używaj nolock, ponieważ indeks umożliwi wydajne pobieranie.

Jeśli podejrzewasz, że wiersz może się zmienić, gdy zapytanie jest uruchomione, i zależy Ci na dokładności, nie używaj nolock.

Jeśli rozważasz NOLOCK z powodu zakleszczeń, sprawdź strukturę planu kwerend pod kątem nieoczekiwanych skanów tabel, prześledź zakleszczenia i zobacz, dlaczego się pojawiają. NOLOCK wokół zapisów może oznaczać, że zapytania, które wcześniej były zakleszczone, mogą potencjalnie zarówno napisać błędną odpowiedź.

Andrew Hill
źródło
2

Lepszymi rozwiązaniami, jeśli to możliwe, są:

  • Replikuj dane (za pomocą replikacji dziennika) do bazy danych raportowania.
  • Użyj migawek sieci SAN i zainstaluj spójną wersję bazy danych
  • Użyj bazy danych, która ma lepszy podstawowy poziom izolacji transakcji

Poziom izolacji transakcji SNAPSHOT został utworzony, ponieważ firma MS traciła sprzedaż na rzecz Oracle. Oracle używa dzienników cofania / ponawiania, aby uniknąć tego problemu. Postgres używa MVCC. W przyszłości firma MS Heckaton będzie używać MVCC, ale to jeszcze lata od przygotowania do produkcji.

pwy
źródło
Powyżej jest literówka. Mam na myśli "lepszy fundamentalny mechanizm izolacji transakcji".
pwy,
1
Poziom izolacji transakcji SNAPSHOT to wynalazek firmy MS. Zasadniczo umieszcza dane w tabeli tymczasowej w TEMPDB. Ta baza danych jest współdzielona przez wszystkie DB w pudełku. Więc jeśli to możliwe, będziesz chciał używać dysków SSD do TEMPDB. To prawdopodobnie mniej wysiłku niż w przypadku innych opcji.
pwy,
1

NOLOCK jest często wykorzystywany jako magiczny sposób na przyspieszenie odczytu bazy danych, ale staram się go unikać, gdy tylko jest to możliwe.

Zestaw wyników może zawierać wiersze, które nie zostały jeszcze zatwierdzone, które często są później wycofywane.

Zestaw błędów lub wyników może być pusty, brakować wierszy lub wyświetlać ten sam wiersz wiele razy.

Dzieje się tak, ponieważ inne transakcje przenoszą dane w tym samym czasie, gdy je czytasz.

PRZECZYTAJ ZATWIERDZONO dodaje dodatkowy problem polegający na uszkodzeniu danych w jednej kolumnie, gdy wielu użytkowników jednocześnie zmienia tę samą komórkę.

WonderWorker
źródło
-2

W prawdziwym życiu, gdy napotykasz systemy już napisane i dodawanie indeksów do tabel, a następnie drastycznie spowalnia ładowanie danych tabeli danych 14gig, czasami jesteś zmuszony do korzystania z NOLOCK w raportach i przetwarzania na koniec miesiąca, aby zagregowane funkcje (suma , count itp.) nie blokują wierszy, stron, tabel i nie wpływają negatywnie na ogólną wydajność. Łatwo powiedzieć, że w nowym systemie nigdy nie używaj funkcji WITH NOLOCK i nie używaj indeksów - ale dodanie indeksów poważnie obniża ładowanie danych, a kiedy zostaniesz poinformowany, zmień bazę kodu, aby usunąć indeksy, a następnie załaduj zbiorczo, a następnie ponownie utwórz indeksy - co wszystko dobrze, jeśli tworzysz nowy system. Ale nie wtedy, gdy masz już system.

user6699628
źródło
1
co ty mówisz
Max Alexander Hanna,