Konkurs książkowy
Nie wiem czy wiecie ale właśnie jestem w trakcie przeprowadzki z Warszawy do Torunia – w związku z tym robię małą inwentaryzację książek jakie mam na półkach. Kilka z nich postanowiłem oddać osobom którym się bardziej przydadzą. Książki dotyczą SQL Server 2005 – jest to seria Step-by-Step oraz kilka innych pozycji (chyba Programming SQL Server, Applied Techniques i coś tam jeszcze – nie pamiętam dokładnie).
Zasady konkursu są jasne – 1 pytanie tygodniowo – jedna książka tygodniowo. Kto pierwszy udzieli satysfakcjonującej odpowiedzi ten wybiera sobie książkę z tych co są do wybrania. Odpowiedzi udzielamy tutaj w komentarzach. Myślę że o ewentualnych odpowiedziach możemy dyskutować na forum WSS.pl. Jeśli nie określono inaczej odpowiedzi będa weryfikowane na SQL Server 2008 SP1.
Pytanie pierwsze:
Jaka jest różnica pomiędzy predykatami IN/EXISTS (NOT IN/NOT EXISTS) – odpowiedź powinna zawierać informację o tym czy występują jakieś (jakie?) różnice w logice, wydajności działania?
Czas na odpowiedzi: poniedziałek, 24 sierpnia 2009 – 20:00.
EDIT:
Komentarze są moderowane – tzn. że muszę je zaakceptować żeby były widoczne. Plan jest taki że będę akceptował jak leci wszystkie odpowiedzi – być może wywiąże się dyskusja np. jeśli jakaś odpowiedź będzie niepełna to tu na blogu padnie wyjaśnienie osoby, która ma inne zdanie. Po zakończeniu każdego pytania – czyli w poniedziałek wieczorem wybiorę odpowiedź, która była najszybsza i najlepsza.
Powodzenia!!!
Comments are closed.
IN sprawdza czy to czego szukamy znajduje się w podzbiorze zwracanym przez podzapytanie, wiec trzeba wyrzucić i sprawdzić
cały podzbiór, żeby spasować dokładnie.
EXISTS sprawdza czy podzbiór z podzapytania w ogóle istnieje, więc wystarczy że zostanie zwrócony pierwszy dowolny wiersz.
Wniosek jest taki, że EXISTS jest zdecydowanie wydajniejsze, z tym, że jego działanie jest ciut inne niż IN, więc trzeba uważać …
IN:
Zwraca prawde jeśli podana wartość pasuje do dowolnej wartości w zapytaniu lub liście
przyjmuje listę lub listę pochodzącą z podzapytania
może być dużo mniej wydajne i wywalić się z błędami przy dużej ilości danych
Exists:
zwraca prawde jeśli podzapytanie zawiera jakieś rekordy
przyjmuje podzapytanie
IN /EXISTS nic ponad to co napiasał kolega marecki
NOT IN/NOT EXISTS – NOT IN nie może używać indexów tylko skany
poza tym w NOT IN jest kwestia nulli – nie zostanie zwrócony żaden wiersz jeśli w tabeli ‘drugiej’ wystąpi null.
P.S. Fajnie że komentarze są moderwane i dostępne po akceptacji ale IMHO powinny byc ujawnione dopiero po zakończeniu konkursu .
Pozdrawiam
Nie przeczytałem jeszcze wśród komentarzy poprawnej (wg mnie) odpowiedzi – proszę o poparcie waszych tez zapytaniami, które potwierdzą to co mówicie. Pracujemy na bazie AdventureWorks2008.
To i ja swoje dorzucę:
1. Plany wykonania zapytań już chyba od wersji SS2000 a na pewno od wersji 2005 są generowane przez optrymalizator w identyczny sposób zarówno dla EXISTS jak i IN pod warunkiem, iż “zdania są logicznie tożsame – równoważne”.
2. Zasadnicza różnica polega na tym iż predykat IN opiera się na logice trójwartościowej, więc poza wartościami prawda i fałsz, występuje również wartość “nieznana”. W przypadku EXISTS występują jedynie wartości prawda i fałsz.
3. Dla logiki normalnej nie ma to znaczenia czy używamy logiki dwuwartościowej czy trzywartościowej,w przypadku odwróconej logiki mamy do czynienia z faktem iż coś nie jest prawdą a po za negowaniu ją nadal nie jest! Dlatego działanie NOT EXISTS i NOT IN mogą przyjmować inne wartości dla wydawałoby się równoważnych zdań.
Chyba wyjaśniłem starając się nie pisać językiem matematycznym :)
Witam, muszę przyznać iż pytanie nie należy do najłatwiejszych, ponieważ większość programistów nie widzi różnicy pomiędzy predykatami IN/EXISTS. Myślę, że znam odpowiedź na to pytanie, poniżej wymieniam różnice:
IN / EXISTS:
– Zaczynając od historii, przed ukazaniem się SQL Server 2000 była istotna różnica pomiędzy generowaniem planu wykonania dla predykatów EXISTS i IN. Zapytania z predykatem EXISTS były bardziej wydajne. (Teraz raczej takiej różnicy nie zauważymy)
– Predykat EXISTS może zwrócić tylko wartość TRUE lub FALSE. Nie rozróżnia wartości UNKNOWN. Natomiast Predykat IN może zwrócić wartości o logicznej wartości UNKNOWN. (Mimo tej różnicy, wartość UNKNOWN jest traktowana przez optymalizator jako wartość FALSE, dlatego też w planach wykonania nie zauważymy różnicy)
– Użycie symbolu „*” np.: … AND EXISTS (SELECT * FROM Tabela as T2 WHERE T1.ID=T2.ID) jest w tym przypadku prawidłowe (mimo iż nie zaleca się stosowania znaku „*”), ponieważ dla predykatu EXISTS tylko odnalezienie jakiegokolwiek istniejącego wiersza jest istotne. Natomiast Predykat IN odwołuje się do konkretnej wartości kolumny z tabeli np.: … AND ID T1.IN (SELECT T2.ID FROM Tabela as T2)
NOT IN / NOT EXISTS:
– Główną różnicą pomiędzy predykatami widać w planach wykonania, otóż predykat NOT EXISTS w planie zapytania będzie posiadał operatora TOP, ponieważ odnalezienie chociażby jednego pasującego wiersza daje wynik FALSE (który w naszym przypadku będzie TRUE). Natomiast predykat NOT IN musi przeskanować całą kolumnę.
– Również różnicę możemy zobaczyć, gdy w kolumnie jest wartość NULL. Dla predykatu NOT EXISTS wartość NULL w kolumnie nie ma żadnego wpływu na rezultat. Natomiast dla predykatu NOT IN w równoważnym zapytaniu, gdzie wystąpi wartość NULL, zwróci zbiór pusty. (Gdy dla tabeli jest dopuszczona wartość NULL, należy uważać. Jeżeli używamy predykatu NOT IN, aby zapobiec złym rezultatom i ulepszyć plan zapytania, należy umieścić filtr, który odrzuca wartości NULL)
Nie mogę zaprzeczyć, iż po części musiałem sobie przypomnieć jak wygląda sytuacja z planami wykonywania, ale kto z nas nie korzysta z innych pomocy naukowych (chociażby BOOKS ONLINE). Na co dzień mam do czynienia z predykatami IN/EXISTS stąd też większość różnić znam. Mam nadzieję, iż moja odpowiedź była satysfakcjonująca.
Niestety na komputerze z którego piszę nie mam silnika SQL, stąd też nie przedstawiłem konkretnych przykładów opartych o bazę AdventureWorks2008. Jeżeli byłaby taka potrzeba mogę postarać się jutro przedstawić kilka przykładów, chociaż niewiem czy będę miał trochę wolnego czasu w pracy. Mama nadzieję, że i tak, odpowiedź jest wystarczająca.
dodam jeszcze od siebie, że IN oraz EXISTS, (jak również ‘=‘, ‘’, ‘=‘ oraz BETWEEN i warunkowo LIKE) są akroninami SARG (search arguments), co oznacza, że są silnie wspierane przez qoptimiazer. Zaś zaprzeczenia powyższego, tj. NOT EXISTS, NOT IN nie są akroninami SARG, a więc na ogół zapytanie z ich użyciem nie zostanie prawidłowo (wydajnie, poprzez nie użycie prawidłowo indeksów etc.) wykonane przez silnik SQL.
Przedstawiam przykłady równoważnych zapytań w których, w pierwszym z nich (NOT IN) otrzymamy zbiór pusty, natomiast w drugim (NOT EXISTS) otrzymamy prawidłowy rezultat.
SELECT DISTINCT City FROM Person.Address O1
WHERE O1.AddressLine2 NOT IN (SELECT O2.AddressLine2 From Person.Address O2)
–W tym przykładzie widać również użycie “*” (gwiazdki)
SELECT DISTINCT City FROM Person.Address O1
WHERE NOT Exists (SELECT * FROM Person.Address O2 WHERE O1.AddressLine2=O2.AddressLine2)
Aby zapobiec tego typu sytuacji należy dla predykatu NOT IN dodać filtr, który wyrzuci NULL’e.