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.
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.
Jako tymczasową poprawkę zmieniłem ją, aby wykonać count (*) i przypisać tę wartość do zmiennej
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 alternatywnego SELECT TOP (1)
sformułowania próbowano. To może być lepsze niż użycie COUNT(*)
, 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:
DECLARE @Exists bit;
SELECT @Exists =
CASE
WHEN 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]
)
THEN CONVERT(bit, 1)
ELSE CONVERT(bit, 0)
END
OPTION (QUERYTRACEON 4138);
IF @Exists = 1
BEGIN
...
END;
IF NOT EXISTS (...) BEGIN END ELSE BEGIN <do something> END
.