2009-11-02 10 views
33

Niedawno dowiedziałem się o istnieniu nowej klauzuli "EXCEPT" w SQL Server (trochę późno, wiem ...) za pośrednictwem kodu odczytu napisanego przez współpracownika. Naprawdę mnie zadziwiło!Kiedy używać EXCEPT zamiast NOT EXISTS w Transact SQL?

Ale wtedy mam kilka pytań dotyczących jego użycia: kiedy jest zalecane zatrudnienie? Czy jest różnica między wydajnością, a wykorzystaniem skorelowanej kwerendy z "AND NOT EXISTS ..."?

Po przeczytaniu artykułu WYJŚCIE w BOL, myślałem, że to tylko skrót do drugiej opcji, ale był zaskoczony, gdy przepisałem kilka zapytań z niego korzystających (więc mieli składnię "AND NOT EXISTS" o wiele bardziej znaną dla mnie), a następnie sprawdzone plany wykonania - niespodzianka! Wersja EXCEPT miała krótszy plan wykonania, a także szybciej. Czy to zawsze tak jest?

Więc chciałbym wiedzieć: jakie są wytyczne dotyczące korzystania z tego potężnego narzędzia?

+0

Dobry odnośnik: http://explainextended.com/2009/09/15/not-in-vs-not-exists-vs -left-join-is-null-sql-server/ –

+0

@rexem: Twoje referencje nigdy nie wspominają o klauzuli EXCEPT ... –

+0

Nie, ale mówi się o NOT EXISTS wydajność. Strona jest również doskonałym odnośnikiem do powiązanych pytań dotyczących wydajności db. –

Odpowiedz

2

Nie ma rozliczania planów wykonania serwera SQL. Zawsze stwierdzałem, że problemy z wydajnością były całkowicie arbitralne (z perspektywy użytkownika, jestem pewien, że autorzy algorytmu zrozumieliby, dlaczego), gdy jedna składnia tworzy lepszy plan wykonania, a nie inny.

W tym przypadku coś w porównaniu z porównywaniem parametrów zapytania umożliwia SQLowi znalezienie skrótu, którego nie mógłby uzyskać z prostej instrukcji wyboru. Jestem pewien, że jest to niedobór algorytmu. Innymi słowy, możesz logicznie interpolować to samo, ale algorytm nie czyni tego tłumaczenia na istniejącym zapytaniu. Czasami dzieje się tak dlatego, że algorytm, który mógł go w niezawodny sposób wykonać, trwałby dłużej niż sam wynik zapytania lub przynajmniej tak pomyślał projektant algorytmu.

33

EXCEPT traktuje wartości NULL jako dopasowanie.

To zapytanie:

WITH q (value) AS 
     (
     SELECT NULL 
     UNION ALL 
     SELECT 1 
     ), 
     p (value) AS 
     (
     SELECT NULL 
     UNION ALL 
     SELECT 2 
     ) 
SELECT * 
FROM q 
WHERE value NOT IN 
     (
     SELECT value 
     FROM p 
     ) 

zwróci pusty zestaw wierszy.

Zapytanie:

WITH q (value) AS 
     (
     SELECT NULL 
     UNION ALL 
     SELECT 1 
     ), 
     p (value) AS 
     (
     SELECT NULL 
     UNION ALL 
     SELECT 2 
     ) 
SELECT * 
FROM q 
WHERE NOT EXISTS 
     (
     SELECT NULL 
     FROM p 
     WHERE p.value = q.value 
     ) 

powróci

NULL 
1 

, a ten:

WITH q (value) AS 
     (
     SELECT NULL 
     UNION ALL 
     SELECT 1 
     ), 
     p (value) AS 
     (
     SELECT NULL 
     UNION ALL 
     SELECT 2 
     ) 
SELECT * 
FROM q 
EXCEPT 
SELECT * 
FROM p 

powróci:

1 

Recursive odniesienia jest także dozwolone w EXCEPT klauzuli w rekurencyjnej CTE, choć zachowuje się w dziwny sposób: zwraca wszystko z wyjątkiem ostatnim rzędzie poprzedniego zestawu, nie wszystko z wyjątkiem całego poprzedniego zestawu:

WITH q (value) AS 
     (
     SELECT 1 
     UNION ALL 
     SELECT 2 
     UNION ALL 
     SELECT 3 
     ), 
     rec (value) AS 
     (
     SELECT value 
     FROM q 
     UNION ALL 
     SELECT * 
     FROM (
       SELECT value 
       FROM q 
       EXCEPT 
       SELECT value 
       FROM rec 
       ) q2 
     ) 
SELECT TOP 10 * 
FROM rec 

--- 
1 
2 
3 
-- original set 
1 
2 
-- everything except the last row of the previous set, that is 3 
1 
3 
-- everything except the last row of the previous set, that is 2 
1 
2 
-- everything except the last row of the previous set, that is 3, etc. 
1 

SQL Server programiści musieli po prostu zapomnieć o tym zakazać.

+0

Również 'except' zwraca Set, a więc różne wartości. – Magnus

2

EXCEPT porównuje wszystkie (sparowane) kolumny dwóch pełnych zaznaczeń. Funkcja NOT EXISTS porównuje dwie lub więcej tabel zgodnych z warunkami określonymi w klauzuli WHERE w podfunkcjach następujących słów kluczowych NOT EXISTS.

EXCEPT można przepisać, używając opcji NOT EXISTS. (lecz wszystkie mogą być zapisane za pomocą ROW_NUMBER i NIE ISTNIEJE.)

Got to od here

8

Zrobiłem wiele analiz z wyjątkiem, nie istnieje, a nie w lewo i sprzężenie zewnętrzne. Zasadniczo lewe sprzężenie zewnętrzne jest najszybsze do znalezienia brakujących wierszy, zwłaszcza dołączenie do klucza podstawowego. Not In może być bardzo szybkie, jeśli wiesz, że będzie to mała lista zwrócona w select.

Używam WYJĄTKOWO wiele, aby porównać to, co jest zwracane podczas przepisywania kodu. Uruchom stary kod, zapisując wyniki. Uruchom nowy kod, zapisując wyniki, a następnie użyj, z wyjątkiem do wychwycenia wszystkich różnic. Jest to bardzo szybki i łatwy sposób na znalezienie różnic, zwłaszcza gdy potrzebujesz uzyskać wszystkie różnice, w tym wartość zerową. Bardzo dobry do łatwego kodowania w locie.

Ale każda sytuacja jest inna. Mówię do każdego programisty, którego kiedykolwiek prowadziłem. Spróbuj. Wykonuj pomiary na różne sposoby. Spróbuj, czas to, zrób to.

2

Jeśli twoje zapytanie jest dostrojone, to nie ma różnicy w wydajności b/w użyciu klauzuli EXCEPT i NOT EXIST/NOT IN .. po raz pierwszy, gdy uruchomiłem EXCEPT po zmianie mojego skorelowanego zapytania do niego .. Byłem zaskoczony, ponieważ powrócił z wynikiem zaledwie w 7 sekund, gdy skorelowane zapytanie powracało w ciągu 22 sekund .. następnie użyłem odrębnej klauzuli w moim skorelowanym zapytaniu i ponownie ... ono również powróciło w 7 sekund .. więc ZWOLNIENIE jest dobre, gdy nie wiesz lub nie masz czasu, aby dostroić zapytanie, w przeciwnym razie są one jednakowo wydajne.

Powiązane problemy