SQL Server NOLOCK i dołącza


153

Tło: Mam zapytanie krytyczne dla wydajności, które chciałbym uruchomić i nie obchodzą mnie brudne odczyty.

Moje pytanie brzmi; Jeśli używam złączeń, czy muszę również określać wskazówkę NOLOCK?

Na przykład; jest:

SELECT * FROM table1 a WITH (NOLOCK)
INNER JOIN table2 b WITH (NOLOCK) ON a.ID = b.ID

Równoważny:

SELECT * FROM table1 a WITH (NOLOCK)
INNER JOIN table2 b ON a.ID = b.ID

A może będę musiał określić (NOLOCK)wskazówkę dotyczącą łączenia, aby upewnić się, że nie blokuję połączonej tabeli?

Odpowiedzi:


166

Nie odniosę się do READ UNCOMMITTEDargumentu, tylko do twojego pierwotnego pytania.

Tak, potrzebujesz WITH(NOLOCK)na każdej tabeli łączenia. Nie, twoje zapytania nie są takie same.

Spróbuj tego ćwiczenia. Rozpocznij transakcję i wstaw wiersz do tabeli 1 i tabeli 2. Nie zatwierdzaj jeszcze ani nie wycofuj transakcji. W tym momencie pierwsze zapytanie zwróci się pomyślnie i będzie zawierać niezatwierdzone wiersze; Twoje drugie zapytanie nie zwróci, ponieważ tabela2 nie zawiera WITH(NOLOCK)podpowiedzi.


18

Byłem prawie pewien, że musisz określić NOLOCKdla każdego JOINw zapytaniu. Ale moje doświadczenie ograniczało się do SQL Server 2005.

Kiedy wyszukałem MSDN tylko w celu potwierdzenia, nie mogłem znaleźć nic konkretnego. Poniższe stwierdzenia wydają się skłaniać mnie do myślenia, że ​​w 2008 r. Dwa powyższe stwierdzenia są równoważne, chociaż w przypadku 2005 r. Tak nie jest:

[SQL Server 2008 R2]

Wszystkie wskazówki dotyczące blokad są propagowane do wszystkich tabel i widoków, do których ma dostęp plan kwerend , w tym do tabel i widoków, do których istnieją odniesienia w widoku. Ponadto SQL Server przeprowadza odpowiednie testy spójności blokad.

[SQL Server 2005]

W SQL Server 2005 wszystkie wskazówki dotyczące blokad są propagowane do wszystkich tabel i widoków, do których istnieją odniesienia w widoku. Ponadto SQL Server przeprowadza odpowiednie testy spójności blokad.

Dodatkowo należy zwrócić uwagę - i dotyczy to zarówno lat 2005, jak i 2008:

Wskazówki dotyczące tabeli są ignorowane, jeśli plan kwerend nie uzyskuje dostępu do tabeli. Może to być spowodowane tym, że optymalizator w ogóle nie chce uzyskiwać dostępu do tabeli lub zamiast tego uzyskuje się dostęp do widoku indeksowanego. W tym drugim przypadku dostęp do widoku indeksowanego można uniemożliwić za pomocą OPTION (EXPAND VIEWS)wskazówki dotyczącej zapytania.


@In Sane: Ciekawe ... dzięki za to ... Zakładam, że nie wyrządzam krzywdy, umieszczając to na STOJACH, nawet jeśli nie jest to całkowicie konieczne? Jak wspomniałeś, dokumentacja NOLOCK jest dość skąpa; Sam nie mogłem znaleźć niczego rozstrzygającego.
DanP,

2
@InSane: Skąd masz te informacje? Wydaje się, że jest to sprzeczne z przyjętą odpowiedzią.
Jay Sullivan

1
@notfed - refer technet link technet.microsoft.com/en-us/library/ms187373(v=sql.105).aspx - możesz zmienić wersję bazy danych u góry, aby porównać ten sam artykuł dla różnych wersji bazy danych
Jagmag

2
Tekst z 2005 roku mówi o WIDOKACH. Więc jeśli zrobisz „from myview with (nolock)”, to mówi, że nolock jest propagowany do wszystkich tabel i widoków zaangażowanych w myview (możesz mieć tam 10 złączeń). Nie jestem pewien, co dokładnie oznacza tekst 2008, ponieważ oprócz widoków dodaje „dostęp przez plan zapytania”.
Thierry_S

9

Ani. Ustawiasz poziom izolacji, READ UNCOMMITTEDktóry jest zawsze lepszy niż podawanie indywidualnych wskazówek dotyczących blokady. Lub, jeszcze lepiej, jeśli zależy Ci na szczegółach, takich jak spójność , użyj izolacji migawki .


@Remus: Nie jestem pewien, czy mogę użyć funkcji READ UNCOMMITTED w moim przypadku, ponieważ uzyskuję dostęp do połączenia przez NHibernate, aby wykonać specjalne surowe wywołanie ADO.NET; czy można to określić bezpośrednio w zapytaniu, czy też będzie zgodne z poziomem transakcji obecnym w transakcji NHibernate?
DanP

Zwiń połączenie using (TransactionScope scope=new TransactionScope(..., TransactionOptions) {...}i ustaw IsolationLevelopcje: msdn.microsoft.com/en-us/library/…
Remus Rusanu

@Remus: Niestety, zarządzanie transakcjami jest obsługiwane na znacznie wyższym poziomie, więc to też nie wchodzi w grę.
DanP,

Widzę. Następnie, aby odpowiedzieć na twoje pytanie: NOLOCK jest wskazówką do tabeli i jako taka ma zastosowanie do zestawu wierszy, do którego jest dodawany (tabela, widok, TVF itp.). Jeśli masz wiele zestawów wierszy połączonych w zapytaniu, każdy z nich będzie potrzebował własnej wskazówki NOLOCK.
Remus Rusanu

2
Ale czy rozważałeś izolację migawek? ALTER DATABASE ... SET READ_COMMITTED_SNAPSHOT ON;. Wyniki są spektakularne, ponieważ wszystkie normalne, zatwierdzone odczyty zamieniają się w odczyty migawkowe, bez blokad, ale spójne. Koszt to zwiększone tempdbobciążenie: msdn.microsoft.com/en-us/library/ms175492.aspx
Remus Rusanu
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.