Optymalizacja zapytań w SQL Server: 8 zmian, które najczęściej przyspieszają SELECT

Jak przyspieszyć SELECT w SQL Server bez zgadywania? Poznaj 8 najczęstszych zmian: analiza planu wykonania, SARGability, indeksy, statystyki, JOIN-y i parametryzacja.
06 września 2026
blog

Od czego zacząć optymalizację zapytania w SQL Server, żeby nie strzelać na ślepo?

Najpierw trzeba ustalić, co dokładnie jest wolne i dlaczego. Optymalizacji nie zaczyna się od przypadkowego dodawania indeksów ani przepisywania całego SELECT-a, tylko od zebrania faktów: czasu wykonania, liczby odczytów logicznych, planu wykonania oraz parametrów, z jakimi zapytanie zostało uruchomione. Dopiero taki komplet pokazuje, czy problemem jest skanowanie dużych tabel, kosztowne sortowanie, nietrafione oszacowania liczby wierszy, blokowanie, czy na przykład zły dobór planu dla konkretnych parametrów.

W praktyce pierwszy krok to uruchomienie problematycznego zapytania z włączonymi statystykami typu SET STATISTICS IO, TIME ON i sprawdzenie rzeczywistego planu wykonania. Plan pokazuje, które operacje są najdroższe i gdzie SQL Server przetwarza najwięcej danych, a statystyki IO i TIME pozwalają odróżnić problem procesora od problemu nadmiernych odczytów. To ważne, bo dwa zapytania o podobnym czasie wykonania mogą mieć zupełnie inną przyczynę spowolnienia.

Trzeba też porównać, ile wierszy optymalizator przewidywał, a ile faktycznie przetworzono. Jeśli te wartości mocno się różnią, problem często nie leży w samym SQL-u, tylko w jakości statystyk, konstrukcji predykatów albo parametryzacji. Bez tej weryfikacji łatwo poprawić objaw, a nie przyczynę.

Dobry punkt startowy to także zawężenie analizy do jednego konkretnego przypadku: tej samej wersji zapytania, tych samych parametrów i podobnego obciążenia. Jeśli raz działa szybko, a raz wolno, trzeba najpierw ustalić, czy winny jest plan wykonania, dane wejściowe albo warunki pracy serwera. Optymalizacja ma sens dopiero wtedy, gdy porównujesz powtarzalny problem, a nie pojedynczy incydent.

Krótko: żeby nie strzelać na ślepo, zacznij od pomiaru, potem obejrzyj rzeczywisty plan wykonania, a na końcu oceniaj zmiany na podstawie tych samych metryk. W SQL Server najszybciej wygrywa nie ta poprawka, która „wydaje się dobra”, tylko ta, która realnie zmniejsza liczbę odczytów, koszt operacji i czas wykonania.

Jak czytać plan wykonania i na co patrzeć w pierwszej kolejności?

Plan wykonania pokazuje, w jaki sposób SQL Server rzeczywiście realizuje zapytanie: skąd pobiera dane, jak je łączy, gdzie sortuje, filtruje i ile pracy wykonuje na poszczególnych etapach. Czytanie planu warto zacząć nie od wszystkich ikon po kolei, ale od miejsc, które najczęściej wskazują realny problem wydajnościowy.

W pierwszej kolejności sprawdza się operatory o najwyższym koszcie, ale z zastrzeżeniem, że procenty w planie są tylko estymacją. To dobra wskazówka, nie wyrok. Jeśli jeden operator ma wyraźnie większy udział niż reszta, to właśnie tam zwykle zaczyna się analiza. Szczególną uwagę zwraca się na Table Scan i Index Scan na dużych tabelach, bo często oznaczają odczyt znacznie większej liczby wierszy niż potrzebna. Nie każdy scan jest błędem, ale przy wolnym SELECT to jeden z pierwszych sygnałów ostrzegawczych.

Drugi kluczowy element to porównanie liczby wierszy estymowanej do rzeczywistej. Jeśli SQL Server przewidział kilka wierszy, a faktycznie przetworzył setki tysięcy, plan mógł zostać oparty na błędnych założeniach. Taka rozbieżność często prowadzi do złego doboru operatorów, niepotrzebnych odczytów i słabego planu dla całego zapytania. Dlatego bardziej użyteczny od samego „kosztu procentowego” bywa właśnie rzeczywisty przepływ wierszy między operatorami.

Następnie warto sprawdzić seeki, scany i lookupy. Index Seek zwykle jest korzystniejszy niż Index Scan, ale sam seek nie gwarantuje dobrego planu, jeśli po nim występuje bardzo wiele odwołań typu Key Lookup. Przy dużej liczbie zwracanych wierszy lookup potrafi stać się jednym z głównych źródeł opóźnienia. W praktyce patrzy się więc nie tylko na typ operatora, ale na to, ile razy został wykonany i ile danych przetworzył.

Kolejny obszar to joiny, sortowanie i hashowanie. Operatory takie jak Nested Loops, Hash Match czy Sort nie są z definicji złe, ale warto zobaczyć, czy zostały użyte przy właściwej skali danych. Jeżeli sort lub hash pracuje na bardzo dużym zbiorze, może generować duże zużycie CPU i pamięci. Jeśli dodatkowo pojawiają się ostrzeżenia o zapisie do tempdb lub nadmiernym przydziale pamięci, to znak, że ten fragment planu wymaga szczególnej uwagi.

Na końcu dobrze jest spojrzeć na ostrzeżenia i właściwości operatorów: brakujące indeksy, implicit conversion, spill do tempdb, odczyty równoległe, kosztowne sortowania. Często to właśnie we właściwościach operatora znajduje się najważniejsza informacja, której nie widać po samej ikonie. Najpraktyczniejsze podejście jest więc takie: najpierw znaleźć operator wykonujący najwięcej pracy, potem sprawdzić rzeczywistą liczbę wierszy, a na końcu ocenić, czy sposób dostępu do danych i łączenia tabel jest adekwatny do skali zapytania.

Dlaczego funkcje i konwersje na kolumnach psują wydajność (SARGability) i jak to naprawić?

SARGability oznacza, że predykat w WHERE, JOIN lub HAVING da się wykorzystać do efektywnego przeszukania indeksu. Gdy na kolumnie wykonujesz funkcję albo konwersję, SQL Server często nie może użyć wartości z indeksu wprost, bo najpierw musi przeliczyć wyrażenie dla wielu lub wszystkich wierszy. W praktyce zamiast index seek częściej pojawia się scan, rośnie liczba odczytów logicznych, czas CPU i koszt całego planu.

Typowe przykłady to warunki w rodzaju YEAR(DataZamowienia) = 2024, LEFT(Kod, 3) = 'ABC', UPPER(Miasto) = 'WARSZAWA' albo CAST(Kolumna AS varchar(10)) = '123'. Problem nie polega na samej funkcji jako takiej, tylko na tym, że jest nałożona na kolumnę filtrowaną lub łączoną. Silnik nie może wtedy łatwo odszukać zakresu wartości w indeksie, bo porównuje wynik przekształcenia, a nie oryginalną wartość klucza indeksu.

Podobny efekt dają niejawne konwersje typów. Jeśli porównujesz kolumnę typu liczbowego z tekstem albo datetime z wartością o innym typie, SQL Server może samodzielnie przekonwertować kolumnę zamiast parametru lub stałej. To również psuje SARGability. Często w planie wykonania widać wtedy ostrzeżenie o CONVERT_IMPLICIT.

Naprawa polega na takim zapisaniu warunku, aby kolumna występowała w możliwie „czystej” postaci, a przekształcenie było przeniesione na stronę stałej, parametru albo logiki zakresowej. Zamiast YEAR(DataZamowienia) = 2024 lepiej użyć DataZamowienia >= '20240101' AND DataZamowienia < '20250101'. Zamiast LEFT(Kod, 3) = 'ABC' lepiej użyć warunku dopasowanego do danych, na przykład zakresu lub wzorca, który nadal pozwala użyć indeksu, jak Kod LIKE 'ABC%'. Zamiast konwertować kolumnę w predykacie, należy przekazać parametr w tym samym typie co kolumna.

Jeśli logika biznesowa naprawdę wymaga filtrowania po przekształconej wartości, praktycznym rozwiązaniem bywa kolumna obliczana, najlepiej trwała i zaindeksowana, o ile wyrażenie spełnia wymagania SQL Server. Wtedy koszt obliczenia jest przeniesiony poza samo wykonanie zapytania, a filtr może znów stać się wyszukiwalny indeksowo.

Najważniejsza zasada jest prosta: w warunkach filtrowania i łączenia porównuj kolumny z wartościami tego samego typu i unikaj opakowywania kolumn funkcjami. To jeden z najczęstszych powodów, dla których pozornie poprawne zapytanie działa znacznie wolniej, niż powinno.

💡 Nie nakładaj funkcji ani CAST/CONVERT na kolumnę w WHERE lub JOIN, bo zabierasz optymalizatorowi szansę na seek i prowokujesz scan. Zamiast tego przenieś przekształcenie na parametr/stałą albo przepisz warunek zakresowo; jeśli to konieczne biznesowo, rozważ zaindeksowaną kolumnę obliczaną.

Kiedy SELECT * realnie szkodzi i jak ograniczyć liczbę czytanych danych?

SELECT * szkodzi wtedy, gdy pobiera więcej kolumn, niż są naprawdę potrzebne. W SQL Server oznacza to nie tylko większy wynik zwracany do aplikacji, ale też większy koszt odczytu danych z pamięci lub dysku, więcej przesyłanych bajtów przez sieć i częstsze sięganie do pełnych stron danych zamiast do węższych struktur indeksowych. Problem staje się szczególnie widoczny przy dużych tabelach, częstych zapytaniach, szerokich kolumnach takich jak nvarchar(max), varbinary(max) czy xml, a także wtedy, gdy zapytanie mogłoby zostać obsłużone przez indeks pokrywający, ale przez * musi wykonać dodatkowe odczyty z tabeli.

Najczęstsza realna szkoda polega na tym, że optymalizator nie może ograniczyć odczytu do minimalnego zestawu danych. Jeśli zapytanie potrzebuje tylko 3 kolumn, a tabela ma ich 40, to SELECT * zmusza silnik do pobrania całego wiersza. To zwiększa liczbę logicznych odczytów, zużycie pamięci i czas wykonania. Dodatkowo szerokie wiersze pogarszają wydajność sortowania, haszowania i operacji na tabelach tymczasowych, bo każda kolejna operacja przenosi większy pakiet danych.

Aby ograniczyć liczbę czytanych danych, należy jawnie wskazywać tylko potrzebne kolumny w klauzuli SELECT oraz zawężać liczbę wierszy możliwie wcześnie, przede wszystkim przez precyzyjne warunki w WHERE. W praktyce oznacza to też unikanie pobierania kolumn dużych typów, jeśli nie są potrzebne w danym scenariuszu, oraz projektowanie indeksów tak, by zapytanie mogło zostać obsłużone z samego indeksu bez dodatkowych odczytów do tabeli. Jeśli aplikacja pokazuje listę rekordów, zwykle warto pobrać tylko kolumny potrzebne do listy, a szczegóły dociągać osobnym zapytaniem dopiero po wejściu w konkretny rekord.

SELECT * bywa akceptowalne w jednorazowej diagnostyce, krótkich zapytaniach administracyjnych albo podczas ręcznej eksploracji danych. W kodzie aplikacyjnym, procedurach i raportach jest jednak ryzykowne wydajnościowo i utrudnia kontrolę nad tym, ile danych SQL Server faktycznie musi przeczytać i zwrócić.

Czy EXISTS jest szybsze niż IN i kiedy to ma znaczenie?

W SQL Server odpowiedź brzmi: nie zawsze. W wielu prostych przypadkach EXISTS i IN są optymalizowane do bardzo podobnego planu wykonania, więc różnica wydajności może być zerowa albo pomijalna. Nie warto zakładać z góry, że samo przepisanie IN na EXISTS automatycznie przyspieszy zapytanie.

Różnica zaczyna mieć znaczenie głównie wtedy, gdy sprawdzasz istnienie dopasowania w podzapytaniu, zwłaszcza dla dużych zbiorów danych. EXISTS jest semantycznie dopasowany do takiego scenariusza, bo SQL Server może zakończyć sprawdzanie po znalezieniu pierwszego pasującego wiersza. IN częściej bywa czytelne przy porównaniu z małą listą stałych wartości, ale przy podzapytaniach może prowadzić do mniej korzystnych decyzji optymalizatora, zależnie od danych, indeksów i kształtu zapytania.

Trzeba też pamiętać o różnicy logicznej przy NULL. EXISTS sprawdza, czy podzapytanie zwraca jakikolwiek wiersz, natomiast IN porównuje wartości. Przez to w pewnych przypadkach, szczególnie przy NOT IN, obecność NULL w podzapytaniu może dać nieoczekiwany wynik. Dlatego w praktyce przy warunkach typu „czy istnieje powiązany rekord” często bezpieczniejszym i bardziej przewidywalnym wyborem jest EXISTS.

SytuacjaZwykle lepszy wybórDlaczego
Sprawdzenie, czy istnieje powiązany rekordEXISTSLepiej oddaje intencję i często dobrze skaluje się dla dużych danych
Porównanie do krótkiej listy stałych wartościINJest prostsze i czytelne, a wydajność zwykle nie stanowi problemu
Warunki negujące przy możliwych NULLEXISTSUnika pułapek logicznych typowych dla NOT IN

W praktyce znaczenie ma to wtedy, gdy zapytanie działa na dużych tabelach, podzapytanie zwraca dużo wierszy albo wynik jest częścią krytycznej ścieżki raportu czy API. Jeśli różnica czasu wykonania ma znaczenie biznesowe, trzeba porównać rzeczywiste plany wykonania i statystyki I/O oraz CPU dla obu wersji. Sam operator to za mało — o wydajności ostatecznie decydują dane, indeksy i plan wykonania.

Jak JOIN i kolejność filtrów wpływają na koszt zapytania?

Koszt zapytania w SQL Server silnie zależy od tego, ile wierszy trzeba przetworzyć na kolejnych etapach planu wykonania. JOIN może ten koszt zwiększyć, jeśli łączy duże zbiory bez wystarczająco selektywnych warunków, bo rośnie liczba porównań, odczytów i ewentualnych operacji sortowania lub haszowania. Im wcześniej silnik może ograniczyć liczbę wierszy, tym mniejszy jest koszt dalszych połączeń.

W praktyce ważne jest rozróżnienie między logiczną kolejnością zapisu a tym, co zrobi optymalizator. W SQL Server kolejność tabel w klauzuli FROM ani kolejność warunków w WHERE zwykle nie narzuca rzeczywistej kolejności wykonania. Optymalizator sam wybiera plan, próbując obniżyć koszt na podstawie statystyk, indeksów i przewidywanej liczby wierszy. To oznacza, że przestawienie warunków typu A AND B najczęściej nic nie zmienia samo w sobie.

Znaczenie ma natomiast to, czy filtr da się zastosować wcześnie i tanio. Jeśli warunek jest selektywny i wspierany przez indeks, SQL Server może najpierw zawęzić dane, a dopiero potem wykonać JOIN. Jeśli filtr jest niesargowalny, oparty na funkcji na kolumnie albo dotyczy wyniku połączenia, silnik może być zmuszony do przetworzenia większej liczby wierszy przed odrzuceniem niepotrzebnych rekordów, co podnosi koszt.

Na koszt wpływa też typ połączenia. Dla małych i dobrze przefiltrowanych zbiorów często opłacalny jest Nested Loops, dla większych i nieuporządkowanych danych częściej pojawia się Hash Match, a gdy dane są już posortowane lub łatwe do posortowania, możliwy jest Merge Join. Jeśli zły szacunek liczby wierszy wynika ze słabych statystyk albo nieprecyzyjnych predykatów, SQL Server może wybrać kosztowniejszy rodzaj JOIN niż ten, który byłby optymalny.

Najważniejszy wniosek jest praktyczny: nie chodzi o ręczne „ustawianie” filtrów w odpowiedniej kolejności w kodzie, tylko o to, by warunki były selektywne, możliwe do użycia przez indeksy i umieszczone tak, aby nie zmieniać semantyki zapytania. Szczególną ostrożność trzeba zachować przy LEFT JOIN: przeniesienie filtra z ON do WHERE może nie tylko zmienić koszt, ale też wynik, bo takie zapytanie może zacząć działać jak INNER JOIN.

Jak statystyki i parametryzacja wpływają na dobór planu wykonania?

SQL Server wybiera plan wykonania na podstawie szacunków kosztu, a te w dużej mierze zależą od statystyk oraz od tego, jakie wartości parametrów są znane w momencie kompilacji zapytania. Jeśli estymacja liczby wierszy jest trafna, optymalizator ma większą szansę dobrać właściwą kolejność złączeń, typ operatorów oraz sposób dostępu do danych. Jeśli estymacja jest błędna, może powstać plan poprawny składniowo, ale kosztowny w praktyce.

Statystyki opisują rozkład danych w kolumnach i indeksach. Na ich podstawie silnik ocenia selektywność warunków, czyli ile wierszy prawdopodobnie spełni filtr. Gdy statystyki są nieaktualne, zbyt ogólne albo nie oddają skośnego rozkładu danych, SQL Server może np. założyć, że wynik będzie mały i wybrać Index Seek z wieloma odczytami pomocniczymi, podczas gdy w rzeczywistości lepszy byłby skan lub inna strategia złączeń. To samo działa w drugą stronę: zawyżona estymacja może prowadzić do zbyt „ciężkiego” planu, nadmiernej pamięci przydzielonej na sortowanie lub hash join oraz niepotrzebnie kosztownych operatorów.

Parametryzacja wpływa na plan dlatego, że pierwszy zestaw wartości użyty przy kompilacji często decyduje o planie, który później jest ponownie wykorzystywany. To klasyczny problem parameter sniffing. Jeśli procedura lub zapytanie raz skompiluje się dla bardzo selektywnej wartości parametru, plan może być świetny dla kilku wierszy, ale słaby dla tysięcy lub milionów. Analogicznie plan utworzony dla „dużego” przypadku może być nieefektywny przy bardzo małym wyniku. Problem jest szczególnie widoczny przy kolumnach o nierównym rozkładzie danych.

W praktyce trzeba rozumieć zależność: statystyki odpowiadają za jakość estymacji, a parametryzacja za to, dla jakich wartości ta estymacja została wykorzystana podczas kompilacji planu. Dlatego wolne działanie tego samego zapytania „raz szybko, raz wolno” bardzo często wynika nie z samej treści SQL, lecz właśnie z ponownego użycia planu dobranego pod inne parametry albo z estymacji opartych na słabych statystykach.

Najważniejszy wniosek jest taki, że dobór planu wykonania nie opiera się na rzeczywistej liczbie wierszy, tylko na przewidywaniach optymalizatora. Im lepsze statystyki i im lepiej kontrolowany wpływ parametrów na kompilację, tym większa szansa na stabilny i wydajny plan.

💡 Jeśli to samo zapytanie działa raz szybko, raz wolno, najpierw sprawdź statystyki i czy plan nie został skompilowany dla nietypowych parametrów — to klasyczny ślad parameter sniffingu. Pamiętaj, że optymalizator nie widzi rzeczywistych danych, tylko ich estymację, więc nawet poprawny SQL może dostać fatalny plan przy słabych statystykach.

Jakie zmiany w indeksach najczęściej dają najszybszy efekt w realnych bazach?

W praktyce najszybszy efekt najczęściej daje dodanie brakującego indeksu nieklastrowanego pod konkretne zapytanie, zwłaszcza gdy filtracja odbywa się po kolumnach bez dobrego wsparcia indeksowego. Jeśli SQL Server musi skanować dużą tabelę, a zapytanie zwraca mały wycinek danych, dobrze dobrany indeks pozwala przejść ze skanu do seeka i radykalnie ograniczyć liczbę odczytów.

Bardzo często równie skuteczne jest rozszerzenie istniejącego indeksu o kolumny INCLUDE. To szybka poprawa w sytuacji, gdy operator wyszukania już działa poprawnie, ale plan wykonania ma kosztowne odwołania do danych bazowych przez Key Lookup lub RID Lookup. Dodanie do indeksu kolumn potrzebnych w SELECT, JOIN albo dodatkowych predykatach pozwala zbudować indeks pokrywający i usunąć tysiące lub miliony dodatkowych odczytów.

Kolejna zmiana, która często daje szybki rezultat, to poprawa kolejności kolumn w kluczu indeksu. Największy efekt pojawia się wtedy, gdy na początku indeksu znajdują się kolumny używane w warunkach równości, a dopiero później te wykorzystywane w zakresach, sortowaniu lub grupowaniu. Zły porządek kolumn potrafi sprawić, że indeks formalnie istnieje, ale optimizer nie może go efektywnie użyć.

W realnych systemach duży zysk daje też usunięcie lub zastąpienie zduplikowanych i słabo trafionych indeksów, ale zwykle nie dlatego, że sam SELECT nagle przyspiesza od razu. Efekt polega częściej na ograniczeniu kosztu utrzymania indeksów, mniejszej fragmentacji i mniejszej konkurencji o zasoby. Jeśli jednak kilka podobnych indeksów zostanie zastąpionych jednym lepiej zaprojektowanym, poprawa odczytu bywa natychmiastowa.

Warto też pamiętać, że najszybszy efekt nie zawsze oznacza największą zmianę konstrukcyjną. Często wystarczy indeks na właściwych kolumnach filtra i dołożenie kilku kolumn w INCLUDE, zamiast budować bardzo szeroki indeks. Najbardziej opłacalne zmiany to te, które eliminują pełne skany, kosztowne lookupy i niepotrzebne sortowania, bo to właśnie one najczęściej odpowiadają za odczuwalne spowolnienie zapytań SELECT.

💡 Najszybsze zyski zwykle daje indeks pod konkretne zapytanie: brakujący nonclustered index albo rozszerzenie istniejącego o INCLUDE, gdy plan robi kosztowne Key/RID Lookup. Zanim dodasz nowy szeroki indeks, sprawdź też kolejność kolumn w kluczu — dobre ustawienie często zamienia „indeks istnieje” na „indeks naprawdę działa”.

Najczęściej zadawane pytania i odpowiedzi odnośnie Optymalizacja zapytań w SQL Server: 8 zmian, które najczęściej przyspieszają SELECT

Jak sprawdzić, czy wolny SELECT ma problem z CPU, odczytami czy planem wykonania?

Najpierw trzeba porównać statystyki IO, TIME i rzeczywisty plan wykonania. Dzięki temu da się odróżnić, czy zapytanie traci czas na nadmiernych odczytach logicznych, kosztownych operacjach procesora czy na źle dobranym planie. Sama długość wykonania nie wystarcza, bo dwa podobnie wolne SELECT-y mogą mieć całkowicie inną przyczynę problemu.

Po czym poznać w planie wykonania, że indeks nie pomaga tak, jak powinien?

Najczęściej widać to po scanach na dużych tabelach albo po wielu lookupach mimo użycia seeka. Sam fakt, że plan pokazuje Index Seek, nie oznacza jeszcze dobrej wydajności. Jeśli po seeku pojawia się dużo Key Lookup lub RID Lookup, koszt dodatkowych odczytów może być na tyle duży, że indeks wymaga przebudowy albo rozszerzenia.

Czy samo przepisanie warunku w WHERE może przyspieszyć zapytanie w SQL Server?

Tak, jeśli nowy zapis przywraca SARGability i pozwala użyć indeksu. Największy efekt daje usunięcie funkcji, CAST, CONVERT lub niejawnych konwersji z kolumn filtrowanych i łączonych. W praktyce często pomagają takie zmiany jak:

  • zamiana funkcji daty na warunek zakresowy,
  • przekazanie parametru w tym samym typie co kolumna,
  • użycie wzorca typu LIKE zamiast funkcji na kolumnie.
Kiedy warto rozważyć kolumnę obliczaną zamiast filtrowania po funkcji?

Kolumna obliczana ma sens wtedy, gdy logika biznesowa stale wymaga filtrowania po przekształconej wartości. Jeśli nie da się łatwo przepisać warunku tak, aby kolumna pozostała w czystej postaci, obliczenie można przenieść poza samo wykonanie SELECT-a. Gdy taka kolumna spełnia wymagania SQL Server i zostanie zaindeksowana, filtr może znów działać bardziej efektywnie.

Dlaczego SELECT * utrudnia wykorzystanie indeksu pokrywającego?

SELECT * zmusza SQL Server do pobrania wszystkich kolumn, także tych, których indeks nie zawiera. Wtedy nawet dobrze dobrany indeks może nie wystarczyć do obsługi całego zapytania i silnik musi wykonywać dodatkowe odczyty z tabeli bazowej. To zwiększa liczbę czytanych danych, obciążenie pamięci i koszt dalszych operacji, takich jak sortowanie czy haszowanie.

Czy zmiana kolejności warunków w WHERE albo tabel w FROM naprawdę przyspiesza JOIN-y?

Zwykle nie, bo SQL Server sam wybiera kolejność wykonania na podstawie planu. Znacznie ważniejsze jest to, czy filtry są selektywne, sargowalne i wspierane przez indeksy. W praktyce większe znaczenie mają:

  • jakość statystyk,
  • trafność predykatów,
  • typ wybranego JOIN-a,
  • liczba wierszy przetwarzanych przed odfiltrowaniem danych.
Skąd wiadomo, że problemem jest parameter sniffing, a nie sam kod zapytania?

Najczęstszym sygnałem jest sytuacja, w której to samo zapytanie działa raz szybko, a raz bardzo wolno. Taki wzorzec sugeruje, że plan został skompilowany dla innych parametrów niż te, z którymi uruchamiasz zapytanie teraz. Jeśli dodatkowo widać duże rozbieżności między estymowaną a rzeczywistą liczbą wierszy, przyczyny trzeba szukać w parametryzacji i statystykach.

Jakie zmiany w indeksach najczęściej najszybciej poprawiają wydajność SELECT?

Najczęściej najszybszy efekt daje brakujący indeks nieklastrowany albo rozszerzenie istniejącego indeksu o INCLUDE. Takie poprawki zwykle ograniczają skany i kosztowne lookupy bez przebudowy całego zapytania. Duże znaczenie ma też właściwa kolejność kolumn w kluczu indeksu, bo od niej zależy, czy optimizer faktycznie użyje indeksu w korzystny sposób.

icon

Formularz kontaktowyContact form

Imię *Name
NazwiskoSurname
Adres e-mail *E-mail address
Telefon *Phone number
UwagiComments