SQL został zaprojektowany jako język deklaratywny, a nie proceduralny. Tak więc optymalizator zapytań nie rozważ kolejność predykatów klauzuli WHERE przy określaniu, jak je zastosować.
Prawdopodobnie zamierzam nadmiernie uprościć następującą dyskusję na temat optymalizatora zapytań SQL. Napisałem rok temu w ten sposób (było to mnóstwo zabawy!). Jeśli naprawdę chcesz zagłębić się w nowoczesną optymalizację zapytań, zobacz Dostrajanie SQL , od O'Reilly.
W prostym optymalizatorze zapytań SQL instrukcja SQL jest najpierw kompilowana w drzewo algebry relacyjnej operacje. Każda z tych operacji pobiera jedną lub więcej tabel jako dane wejściowe i generuje inną tabelę jako dane wyjściowe. Skanuj to sekwencyjne skanowanie, które wczytuje tabelę z bazy danych. Sortuj tworzy posortowaną tabelę. Wybierz tworzy tabelę, której wiersze są wybierane z innej tabeli zgodnie z pewnymi warunkami selekcji. Projekt tworzy tabelę z tylko określonymi kolumnami innej tabeli. Krzyż produktów pobiera dwie tabele i tworzy tabelę wyjściową złożoną z każdej możliwej pary wierszy.
Myląco, klauzula SQL SELECT jest kompilowana do algebry relacyjnej Projekt , podczas gdy klauzula WHERE zamienia się w algebrę relacyjną Select . Klauzula FROM zamienia się w jedno lub więcej połączeń , z których każdy bierze dwa stoły i produkuje jeden stół. Istnieją inne operacje algebry relacyjnej związane z sumą zbiorów, przecięciem, różnicą i członkostwem, ale niech to będzie proste.
To drzewo naprawdę wymaga optymalizacji. Na przykład, jeśli masz:
select E.name, D.name
from Employee E, Department D
where E.id = 123456 and E.dept_id = D.dept_id
przy 5000 pracownikach w 500 działach, wykonanie niezoptymalizowanego drzewa na ślepo da wszystkie możliwe kombinacje jednego pracownika i jednego działu (produkt krzyżowy ), a następnie Wybierz tylko jedną kombinację, która była potrzebna. Skan pracowników wytworzy tabelę z 5000 rekordów, Skan działu stworzy tabelę rekordów 500, produkt krzyżowy z tych dwóch tabel wygeneruje 2 500 000 rekordów, a Wybierz na E.id weźmie tę tabelę rekordów 2 500 000 i odrzuci wszystkie oprócz jednego, rekord, który był poszukiwany.
[Prawdziwe procesory zapytań będą oczywiście starały się nie materializować wszystkich tych tabel pośrednich w pamięci.]
Optymalizator zapytań porusza się więc po drzewie i stosuje różne optymalizacje. Jednym z nich jest rozbicie każdego Wyboru w łańcuch wyborów , po jednym dla każdego oryginalnego Wybierz warunki na najwyższym poziomie, te i-ed razem. (Nazywa się to „spójną postacią normalną”). Następnie poszczególne mniejsze Wybiera są przemieszczane w drzewie i łączone z innymi operacjami algebry relacyjnej w celu utworzenia bardziej wydajnych operacji.
W powyższym przykładzie optymalizator najpierw wypycha Wybierz na E.id =123456 poniżej drogiego produktu krzyżowego operacja. Oznacza to produkt krzyżowy po prostu tworzy 500 wierszy (po jednym dla każdej kombinacji tego pracownika i jednego działu). Następnie najwyższy poziom Wybierz for E.dept_id =D.dept_id odfiltrowuje 499 niechcianych wierszy. Nieźle.
Jeśli w polu identyfikatora pracownika znajduje się indeks, optymalizator może połączyć Skanowanie pracowników z Wybierz na E.id =123456, aby utworzyć szybki indeks Lookup . Oznacza to, że z dysku wczytywany jest tylko jeden wiersz pracownika, a nie 5000. Sprawy wyglądają dobrze.
Ostatnia główna optymalizacja polega na wykonaniu Wybierz na E.dept_id =D.dept_id i połącz go z Produktem krzyżowym . Zamienia to w algebrę relacyjną Equijoin operacja. Samo to niewiele daje. Ale jeśli istnieje indeks Department.dept_id, to sekwencyjne Skanowanie niższego poziomu Departamentu karmiącego Equijoin można przekształcić w bardzo szybki indeks Lookup rekordu naszego jednego pracownika działu.
Mniejsze optymalizacje obejmują popychanie projektu operacje w dół. Jeśli najwyższy poziom zapytania wymaga tylko E.name i D.name, a warunki wymagają E.id, E.dept_id i D.dept_id, wtedy Skanowanie operacje nie muszą budować tabel pośrednich ze wszystkimi pozostałymi kolumnami, oszczędzając miejsce podczas wykonywania zapytania. Zmieniliśmy strasznie wolne zapytanie w dwa wyszukiwania indeksu i niewiele więcej.
Przechodząc bardziej do pierwotnego pytania, powiedzmy, że masz:
select E.name
from Employee E
where E.age > 21 and E.state = 'Delaware'
Niezoptymalizowane drzewo algebry relacyjnej, po wykonaniu, przeskanuje 5000 pracowników i wyprodukuje, powiedzmy, 126 pracowników w Delaware, którzy mają więcej niż 21 lat. Optymalizator zapytań ma również pewne przybliżone pojęcie o wartościach w bazie danych. Może wiedzieć, że kolumna E.state zawiera 14 stanów, w których firma ma lokalizacje, oraz coś na temat dystrybucji E.age. Więc najpierw sprawdza, czy któreś z pól jest indeksowane. Jeśli E.state jest, sensowne jest użycie tego indeksu do wybrania niewielkiej liczby pracowników, których procesor zapytań podejrzewa, że znajduje się w Delaware na podstawie ostatnich obliczonych statystyk. Jeśli tak jest tylko E.age, procesor zapytań prawdopodobnie uzna, że nie jest tego wart, ponieważ 96% wszystkich pracowników ma 22 lata i więcej. Jeśli więc E.state jest indeksowany, nasz procesor zapytań łamie Select i łączy E.state =„Delaware” z Skanem aby przekształcić go w znacznie wydajniejsze skanowanie indeksu .
Załóżmy w tym przykładzie, że nie ma indeksów na E.state i E.age. Połączony Wybierz operacja odbywa się po sekwencyjnym „Skanowaniu” Pracownika. Czy ma znaczenie, który warunek w Wybierz? jest zrobione jako pierwsze? Prawdopodobnie nie za dużo. Procesor zapytań może pozostawić je w oryginalnej kolejności w instrukcji SQL lub może być nieco bardziej wyrafinowany i przyjrzeć się oczekiwanym wydatkom. Ze statystyk wynika, że warunek E.state =„Delaware” powinien być bardziej selektywny, więc odwróciłby warunki i zrobił to jako pierwszy, aby było tylko 126 porównań E.age> 21 zamiast 5000 . Może też zdać sobie sprawę, że porównania równości ciągów są znacznie droższe niż porównania liczb całkowitych i pozostawić kolejność w spokoju.
W każdym razie wszystko to jest bardzo złożone i jest bardzo mało prawdopodobne, aby kolejność warunków składniowych miała znaczenie. Nie martwiłbym się tym, chyba że masz prawdziwy problem z wydajnością, a dostawca bazy danych używa kolejności warunków jako podpowiedzi.