Kiedy uruchamiam następujący kod, zajmuje to 22,5 minuty i wykonuje 106 milionów odczytów. Jeśli jednak uruchomię tylko wewnętrzną instrukcję select, zajmuje to tylko 15 sekund i czyta 264k. Na marginesie, wybrane zapytanie nie zwraca żadnych rekordów.
Wiesz, dlaczego IF EXISTS
to sprawi, że będzie działało o wiele dłużej i wykona tak wiele innych odczytów? Zmieniłem także zaznaczone polecenie do wykonania SELECT TOP 1 [dlc].[id]
i zabiłem je po 2 minutach.
Jako tymczasową poprawkę zmieniłem ją, aby wykonać count (*) i przypisać tę wartość do zmiennej @cnt
. Potem robi IF 0 <> @cnt
oświadczenie. Ale pomyślałem EXISTS
, że byłoby lepiej, ponieważ jeśli w instrukcji select zostaną zwrócone rekordy, przestanie wykonywać skanowanie / wyszukiwanie, gdy znajdzie co najmniej jeden rekord, a count(*)
zakończy pełne zapytanie. czego mi brakuje?
IF EXISTS
(SELECT [dlc].[ID]
FROM TableDLC [dlc]
JOIN TableD [d]
ON [d].[ID] = [dlc].[ID]
JOIN TableC [c]
ON [c].[ID] = [d].[ID2]
WHERE [c].[Name] <> [dlc].[Name])
BEGIN
<do something>
END
źródło
IF NOT EXISTS (...) BEGIN END ELSE BEGIN <do something> END
.Odpowiedzi:
Jak wyjaśniłem w mojej odpowiedzi na to powiązane pytanie:
W jaki sposób (i dlaczego) TOP wpływa na plan realizacji?
Użycie
EXISTS
wprowadza cel wiersza, w którym optymalizator tworzy plan wykonania mający na celu szybkie zlokalizowanie pierwszego wiersza. W ten sposób zakłada się, że dane są równomiernie rozmieszczone. Na przykład, jeśli statystyki pokazują, że jest 100 oczekiwanych dopasowań w 100 000 wierszy, zakładamy, że będzie musiał odczytać tylko 1000 wierszy, aby znaleźć pierwsze dopasowanie.Spowoduje to wydłużenie czasu realizacji, jeśli założenie to okaże się błędne. Na przykład, jeśli SQL Server wybierze metodę dostępu (np. Skanowanie nieuporządkowane), która zdarzy się zlokalizować pierwszą pasującą wartość bardzo późno podczas wyszukiwania, może to spowodować prawie całkowite skanowanie. Z drugiej strony, jeśli w pierwszych kilku wierszach znajdzie się pasujący wiersz, wydajność będzie bardzo dobra. Jest to podstawowe ryzyko związane z celami rzędu - niespójne wyniki.
Zazwyczaj możliwe jest przeformułowanie zapytania, tak aby cel wiersza nie został przypisany. Bez celu wiersza zapytanie może zostać zakończone po napotkaniu pierwszego pasującego wiersza (jeśli zostanie poprawnie napisany), ale strategia planu wykonania prawdopodobnie będzie inna (i, mam nadzieję, bardziej skuteczna). Oczywiście count (*) będzie wymagał odczytu wszystkich wierszy, więc nie jest to idealna alternatywa.
Jeśli korzystasz z programu SQL Server 2008 R2 lub nowszego, możesz również ogólnie użyć udokumentowanej i obsługiwanej flagi śledzenia 4138, aby uzyskać plan wykonania bez celu wiersza. Tę flagę można również określić przy użyciu obsługiwanej wskazówki
OPTION (QUERYTRACEON 4138)
, należy jednak pamiętać, że wymaga ona uprawnień administratora środowiska wykonawczego , chyba że jest używana z przewodnikiem planu.Niestety
Żadne z powyższych nie działa z
IF EXISTS
instrukcją warunkową. Dotyczy to tylko zwykłego DML. To będzie pracować z alternatywnegoSELECT TOP (1)
sformułowania próbowano. To może być lepsze niż użycieCOUNT(*)
, które musi liczyć wszystkie kwalifikowane wiersze, jak wspomniano wcześniej.To powiedziawszy, istnieje wiele sposobów wyrażenia tego wymogu, które pozwolą Ci uniknąć celu kontroli wiersza lub go kontrolować, jednocześnie przerywając wyszukiwanie wcześniej. Ostatni przykład:
źródło
Ponieważ EXISTS musi znaleźć tylko jeden wiersz, użyje celu rzędu jednego. Czasami może to spowodować powstanie niezbyt idealnego planu. Jeśli spodziewasz się, że tak będzie dla Ciebie, wypełnij zmienną wynikiem a,
COUNT(*)
a następnie przetestuj tę zmienną, aby sprawdzić, czy jest większa niż 0.Więc ... Przy małym celu wiersza pozwoli uniknąć operacji blokowania, takich jak budowanie tabel skrótów lub sortowanie przepływów, które mogą być przydatne do łączenia złączeń, ponieważ zorientuje się, że musi znaleźć coś dość szybko, a zatem zagnieżdżone pętle bądź najlepszy, jeśli coś znajdziesz. Tyle że może to zrobić plan, który jest znacznie gorszy w całym zestawie. Jeśli znalezienie pojedynczego wiersza było szybkie, chciałbyś tę metodę unikania bloków ...
źródło