Na Client
polu tabeli znajduje się indeks klastrowany LastName
.
Kiedy po prostu zrzucam wszystkie rekordy z tabeli, pojawiają się one w kolejności alfabetycznej, chyba że (nolock)
podpowiedź jest użyta jak w zapytaniu. Ta wskazówka zmienia kolejność rekordów. Powinien? Jestem przekonany, że żadna inna sesja nie zawiera otwartej transakcji ze zmianami w tej tabeli (przynajmniej sp_who2
mnie nie pokazuje).
Jak wyjaśnić różnicę w kolejności?
Dodatkowe informacje pochodzą z komentarzy:
Nie ma zamówienia według. Czy indeks nieklastrowany powinien egzekwować zamówienie?
Zapytania nadal zwracają inną kolejność, nawet gdy używana jest wskazówka dotycząca indeksu określająca indeks klastrowany. Powinni? Zastanawiam się, dlaczego
nolock
zmienia kolejność zwracanych rekordów bez widocznej zmiany planów.Zrobiłem na nich WinDiff - to samo, z wyjątkiem [the]
(nolock)
[wskazówka do zapytania].
Odpowiedzi:
Pojawienie się uporządkowanego zestawu wyników bez
ORDER BY
klauzuli często wynika ze skanu pobierającego wiersze w kolejności indeksu. Jednym z powodów, dla których skanowanie kolejności indeksów jest zwykle wybierane poniżej domyślnegoREAD COMMITTED
poziomu izolacji, jest to, że zmniejsza ryzyko niepożądanych anomalii współbieżności, takich jak wielokrotne napotkanie tego samego wiersza lub całkowite pominięcie niektórych wierszy. Jest to szczegółowo opisane w kilku miejscach, w tym w tej serii artykułów o poziomach izolacji.Dzięki
NOLOCK
podpowiedzi do tabeli zachowanie to jest złagodzone, a dostęp do tabeli odbywa się na bardziej tolerancyjnymREAD UNCOMMITTED
poziomie izolacji, który może skanować dane w kolejności alokacji zamiast w kolejności indeksu. Jak opisano w tym łączu, decyzja o tym, czy użyć skanowania kolejności alokacji, czy skanowania kolejności indeksu, należy do silnika pamięci masowej. Ten wybór może zmieniać się między wykonaniami bez zmiany planu zapytań .Może to zabrzmieć bardzo abstrakcyjnie, ale można to łatwiej zademonstrować za pomocą niektórych zapytań wykorzystujących nieudokumentowane funkcje w bazie danych AdventureWorks2012 .
Zapytania zostały zapożyczone z niewielką modyfikacją od Paula White'a .
Wreszcie, dla jasności, ta odpowiedź dotyczy wyglądu uporządkowanego zestawu wyników. Nie ma gwarantowanej kolejności prezentacji bez najwyższego poziomu
ORDER BY
.Skanowanie kolejności alokacji może wystąpić w różnych innych okolicznościach, na przykład w momencie uzyskania blokady na poziomie tabeli lub gdy baza danych jest w trybie tylko do odczytu. Równoległość może również wpływać na kolejność zwracania danych. Kluczową kwestią jest to, że bez
ORDER BY
tego zwracane dane mogą się zmieniać w czasie w zależności od projektu.źródło
... nie powinieneś oczekiwać żadnego zamówienia. W rzeczywistości to samo zapytanie uruchomione wiele razy może powrócić w innej kolejności bez ostrzeżenia. Powodem jest to, że twoje dwa zapytania - które są „różnymi” zapytaniami najprawdopodobniej z powodu innego tekstu zapytania, a nie z powodu podpowiedzi - mają różne plany wykonania (a różnica może być subtelna, na przykład iterator, który wygląda tak samo w oba plany, ale ma
ordered: true
tylko jeden lub znacznie inną liczbę szacowanych wierszy, ponieważ jeden został skompilowany przed poważną zmianą danych). Może być również tak, że przeprowadzany jest skan zlecenia alokacji, jak słusznie nakreślił James w swojej odpowiedzi.W każdym razie, ponieważ uruchamiasz kwerendę bez
ORDER BY
, SQL Server wnioskuje, że nie obchodzi cię porządek, a więc wyłącza się i określa najbardziej efektywny sposób zwracania wierszy (nie przejmuje się porządkiem, jeśli nie ).Wyjaśnię to bardzo jasno:
Jeśli chcesz lub oczekujesz określonego zamówienia, dodaj klauzulę ORDER BY
Stało się to wcześniej:
I napisałem o tym na blogu:
Oto cytat z tego ostatniego, który przypomina to, co powiedziałem, aby odpowiedzieć na twój komentarz na temat używania podpowiedzi indeksu zamiast
ORDER BY
klauzuli:Conor Cunningham - całkiem sprytny facet, bezpośrednio odpowiedzialny za większość tego, co robi SQL Server, gdy przetwarza dla ciebie zapytanie - napisał o tym tutaj:
Przeczytaj trochę, a następnie dodaj
ORDER BY
klauzulę do swoich zapytań, zanim narzekasz na inne lub nieoczekiwane sortowanie.źródło
James dobrze wyjaśnił, jak to działa, ale chciałbym powtórzyć jedną rzecz: jeśli nie użyjesz funkcji porządkowania, kolejność wierszy w zestawie wyników jest niezdefiniowana . Jeśli potrzebujesz danego zamówienia, użyj wyraźnej
order by
klauzuli - jeśli go nie określisz, w zasadzie mówisz „W ogóle nie obchodzi mnie to zamówienie”, a nie „Zamów przez indeks klastrowany”.źródło