Debugowanie zapytań T-SQL: jak czytać execution plan i STATISTICS IO/TIME
Dowiedz się, jak debugować zapytania T-SQL za pomocą execution plan oraz STATISTICS IO/TIME. Praktyczne wskazówki i techniki optymalizacji.
Wprowadzenie do analizy wydajności zapytań T-SQL
Wydajność zapytań T-SQL odgrywa kluczową rolę w efektywnym działaniu aplikacji korzystających z Microsoft SQL Server. Problemy z wydajnością mogą prowadzić do długiego czasu odpowiedzi, przeciążenia serwera oraz niezadowolenia użytkowników końcowych. Dlatego zrozumienie, jak diagnozować i optymalizować zapytania, jest niezbędne dla administratorów baz danych, programistów i analityków BI.
Analiza wydajności zapytań SQL opiera się przede wszystkim na dwóch podstawowych źródłach informacji: planie wykonania (execution plan) oraz danych statystycznych, takich jak STATISTICS IO i STATISTICS TIME. Każde z tych narzędzi dostarcza innego rodzaju danych:
- Plan wykonania pokazuje, w jaki sposób SQL Server interpretuje zapytanie i jakie kroki podejmuje, aby je wykonać. Pozwala to zrozumieć, które operacje są najbardziej kosztowne i gdzie mogą występować wąskie gardła.
- STATISTICS IO i STATISTICS TIME dostarczają informacji o zużyciu zasobów, takich jak liczba odczytów dyskowych czy czas procesora, co pomaga ocenić wpływ zapytania na środowisko wykonawcze.
Umiejętność odczytywania i interpretowania tych danych pozwala nie tylko na identyfikację nieefektywnych fragmentów kodu T-SQL, ale również na podejmowanie świadomych decyzji dotyczących indeksowania, zmian w strukturze zapytań czy modyfikacji schematu bazy danych.
W niniejszym artykule skupimy się na praktycznych aspektach analizy wydajności zapytań w SQL Server, prezentując krok po kroku jak posługiwać się dostępnymi narzędziami i technikami diagnozowania problemów.
Zrozumienie planu wykonania – podstawy i typy operatorów
Plan wykonania (execution plan) to jedno z najważniejszych narzędzi wykorzystywanych w analizie wydajności zapytań T-SQL. Przedstawia on szczegółowy przebieg realizacji zapytania przez silnik SQL Server, pokazując krok po kroku, jak dane są pobierane, filtrowane, sortowane i łączone. Zrozumienie struktury oraz sposobu działania planów wykonania pozwala lepiej diagnozować problemy związane z wydajnością i podejmować trafniejsze decyzje optymalizacyjne. Temat tego artykułu pojawia się w niemal każdej sesji szkoleniowej Cognity – czasem w formie pytania, czasem w formie frustracji.
Plan wykonania może być prezentowany w dwóch głównych formach: graficznej oraz tekstowej. Forma graficzna, dostępna w SQL Server Management Studio, zawiera wizualne przedstawienie operatorów i przepływu danych między nimi. Forma tekstowa – tzw. SHOWPLAN_TEXT lub SHOWPLAN_ALL – to alfanumeryczna reprezentacja tego samego procesu. Obie formy niosą te same informacje, różniąc się jedynie sposobem prezentacji.
W planie wykonania kluczowe znaczenie mają tzw. operatory. Każdy operator reprezentuje określoną akcję wykonaną na danych, np. skanowanie tabeli, sortowanie, filtrowanie lub złączenie. Operatory można podzielić na kilka kategorii, z których najważniejsze to:
- Operatory dostępu do danych – odpowiadają za pozyskanie danych z tabel lub indeksów. Przykłady to Table Scan i Index Seek.
- Operatory przetwarzania danych – wykonują operacje takie jak filtrowanie (Filter), sortowanie (Sort) czy agregacja (Aggregate).
- Operatory złączeń – realizują łączenie zestawów danych przy użyciu różnych algorytmów, np. Nested Loops, Merge Join czy Hash Match.
- Operatory strumieniowania wyników – odpowiadają za przekazywanie danych między operatorami, często wskazują też na ilość przetworzonych wierszy i koszty operacji.
Znajomość podstawowych operatorów i ich roli w planie wykonania pozwala szybko zorientować się, które fragmenty zapytania mogą być źródłem problemów wydajnościowych. W szczególności warto zwracać uwagę na koszt operacji, sposób dostępu do danych oraz ilość przetwarzanych wierszy – to właśnie te czynniki mają największy wpływ na ogólną efektywność zapytania.
Jak odczytywać i interpretować STATISTICS IO i STATISTICS TIME
W procesie analizy wydajności zapytań T-SQL, narzędzia takie jak SET STATISTICS IO i SET STATISTICS TIME dostarczają cennych informacji na temat kosztów operacji wejścia/wyjścia oraz czasu niezbędnego do wykonania zapytania. Choć są to dwa oddzielne mechanizmy diagnostyczne, często stosuje się je razem, by uzyskać pełniejszy obraz obciążenia związanego z wykonaniem zapytania.
Różnice między STATISTICS IO a STATISTICS TIME
| Cecha | STATISTICS IO | STATISTICS TIME |
|---|---|---|
| Zakres informacji | Odczyty i zapisy stron danych z poziomu dysku i pamięci podręcznej | Czas CPU i czas całkowity wykonania zapytania |
| Typ analizy | Wskaźnik intensywności operacji wejścia/wyjścia | Miernik kosztu obliczeniowego i czasu wykonania |
| Najczęstsze zastosowania | Identyfikacja nieefektywnych odczytów z tabel i indeksów | Porównanie wydajności różnych wersji zapytania |
Jak włączyć STATISTICS IO i STATISTICS TIME
Użycie tych opcji jest bardzo proste i nie wymaga żadnych zmian w samych zapytaniach:
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
-- Przykładowe zapytanie
SELECT * FROM Produkty WHERE KategoriaID = 2;
Po wykonaniu zapytania, SQL Server wyświetli w zakładce Messages szczegółowe dane o ilości odczytów logicznych i fizycznych (STATISTICS IO), a także o czasie CPU i czasie rzeczywistym wykonania (STATISTICS TIME).
Dlaczego są ważne
- STATISTICS IO pozwala zlokalizować zapytania, które powodują nadmierne odczyty z tabel lub indeksów — może to wskazywać na brak odpowiednich indeksów lub nieefektywny plan wykonania.
- STATISTICS TIME umożliwia porównanie czasów CPU i czasu rzeczywistego, co może ujawnić problemy z przeciążeniem procesora lub oczekiwaniem na zasoby (np. blokady, dysk).
Kiedy stosować
Analiza tych statystyk jest szczególnie przydatna na etapie optymalizacji zapytań, oceny wpływu zmian indeksów, refaktoryzacji kodu T-SQL lub porównywania alternatywnych wersji zapytania. Dzięki nim można podejmować świadome decyzje dotyczące dalszych działań optymalizacyjnych. Jeśli chcesz lepiej zrozumieć, jak wykorzystać te narzędzia w praktyce i nauczyć się efektywnego pisania zapytań T-SQL, sprawdź Kurs SQL Server - tworzenie skryptów, zapytań i poleceń w T-SQL - poziom od podstaw.
W kolejnych sekcjach przyjrzymy się, jak łączyć te dane z informacjami z planów wykonania oraz jak interpretować konkretne przypadki, by lepiej zrozumieć wąskie gardła zapytań.
Praktyczne przykłady analizy planów wykonania
Analiza planu wykonania (Execution Plan) pozwala zrozumieć, jak SQL Server interpretuje i realizuje zapytania T-SQL. W tej sekcji przedstawimy kilka praktycznych przykładów, które ilustrują, jak różne konstrukcje zapytań wpływają na sposób ich wykonania i wydajność. Na szkoleniach Cognity pokazujemy, jak poradzić sobie z tym zagadnieniem krok po kroku – poniżej przedstawiamy skrót tych metod.
Przykład 1: Różnice między SELECT * a selektywnym wyborem kolumn
-- Przykład A
SELECT * FROM Sales.Orders WHERE OrderDate > '2023-01-01';
-- Przykład B
SELECT OrderID, OrderDate FROM Sales.Orders WHERE OrderDate > '2023-01-01';
W planie wykonania dla przykładu A może wystąpić operator Clustered Index Scan, ponieważ pobierane są wszystkie kolumny, co może prowadzić do pełnego odczytu danych. W przypadku przykładu B, istnieje większa szansa na użycie Index Seek, jeśli istnieje odpowiedni indeks obejmujący kolumny OrderID i OrderDate.
Przykład 2: Porównanie JOIN vs. EXISTS
-- Przykład A: JOIN
SELECT c.CustomerID
FROM Customers c
JOIN Orders o ON c.CustomerID = o.CustomerID;
-- Przykład B: EXISTS
SELECT c.CustomerID
FROM Customers c
WHERE EXISTS (SELECT 1 FROM Orders o WHERE o.CustomerID = c.CustomerID);
Choć oba zapytania zwracają podobne wyniki, plan wykonania może się różnić. JOIN może generować operację Hash Match lub Nested Loops, w zależności od ilości danych i dostępnych indeksów. EXISTS często pozwala na wczesne zakończenie podzapytania, co może przynieść korzyści wydajnościowe przy dużych zbiorach danych.
Przykład 3: Użycie funkcji skalarnych
-- Przykład z funkcją skalarną
SELECT * FROM Sales.Orders WHERE YEAR(OrderDate) = 2023;
Użycie funkcji skalarnej w warunku WHERE może spowodować, że SQL Server nie będzie w stanie efektywnie wykorzystać indeksów. W planie wykonania często pojawi się operator Scan zamiast Seek. Alternatywą może być przekształcenie warunku:
-- Alternatywne podejście
SELECT * FROM Sales.Orders WHERE OrderDate >= '2023-01-01' AND OrderDate < '2024-01-01';
Takie podejście zwiększa szansę na użycie indeksu.
Przykład 4: Użycie DISTINCT vs. GROUP BY
-- Przykład A: DISTINCT
SELECT DISTINCT ProductID FROM Sales.OrderDetails;
-- Przykład B: GROUP BY
SELECT ProductID FROM Sales.OrderDetails GROUP BY ProductID;
Plany wykonania dla obu zapytań mogą być bardzo podobne, ale w przypadku bardziej złożonych obliczeń GROUP BY daje większą kontrolę nad agregacją. Operatorzy tacy jak Stream Aggregate czy Hash Aggregate mogą pojawić się w zależności od sortowania danych wejściowych.
Tabela porównująca typowe operacje a ich wpływ na plan wykonania
| Rodzaj operacji | Typowy operator w Execution Plan | Uwagi |
|---|---|---|
| Wyszukiwanie po indeksie | Index Seek | Efektywne, dostęp do ograniczonej liczby stron |
| Pełne skanowanie tabeli | Table Scan / Clustered Index Scan | Wolniejsze, przetwarza całą tabelę |
| Agregacje | Stream Aggregate / Hash Aggregate | Wybór zależy od sortowania wejścia |
| Łączenie tabel | Nested Loops / Hash Match / Merge Join | Dobór zależny od rozmiarów i indeksów |
Analiza planów wykonania to nie tylko identyfikacja operatorów, ale także zrozumienie, dlaczego zostały wybrane przez optymalizator zapytań. W kolejnych krokach analizy wydajności istotne będzie poznanie metryk i szczegółów kosztów, które pozwolą jeszcze lepiej zrozumieć zachowanie zapytań.
Identyfikacja typowych problemów z wydajnością zapytań
Problemy z wydajnością zapytań w T-SQL mogą mieć różne przyczyny, jednak wiele z nich ma charakter powtarzalny i wynika z nieoptymalnego wykorzystania zasobów serwera SQL lub błędnej konstrukcji zapytań. Poniżej przedstawiamy najczęściej spotykane problemy wraz z krótkim opisem ich objawów i potencjalnych przyczyn.
- Brak indeksów lub ich nieoptymalne wykorzystanie
Objawia się dużą liczbą odczytów logicznych i fizycznych oraz długim czasem wykonania zapytania. Może prowadzić do pełnych skanów tabel (Table Scan) lub indeksów (Index Scan), zamiast bardziej wydajnych operacji typu Seek. - Nieefektywne filtrowanie danych
Zapytania bez odpowiednich warunków WHERE powodują przetwarzanie zbyt dużej ilości danych. Często towarzyszy temu wysoka liczba odczytanych stron i niepotrzebne operacje sortowania lub agregacji. - Nieodpowiedni wybór typu JOIN
Użycie zbyt kosztownych operacji złączeń (np. Nested Loops przy dużych zbiorach danych) może znacząco obciążyć zasoby. Wybór strategii złączenia jest zależny od planu wykonania i rozmiaru danych źródłowych. - Operacje na dużych zbiorach bez podziału na partie
Długie transakcje lub operacje UPDATE/DELETE na milionach wierszy bez podziału na mniejsze porcje mogą prowadzić do blokad, timeoutów i nadmiernego wykorzystania pamięci. - Nieoptymalne korzystanie z funkcji skalarnej lub zagnieżdżonych zapytań
Wbudowane funkcje wywoływane dla każdego wiersza (np. w SELECT lub WHERE) prowadzą do wydłużonego czasu wykonania. Podobnie – zagnieżdżone zapytania wykonywane wielokrotnie (np. w kolumnie SELECT) mogą skutkować nadmierną liczbą operacji IO. - Problemy z parametryzacją i dopasowaniem planów
Nieprawidłowa lub brak parametryzacji może prowadzić do generowania nieoptymalnych planów lub ich nadmiernej liczby w pamięci podręcznej (tzw. plan cache bloat).
Poniższa tabela przedstawia porównanie typowych symptomów oraz potencjalnych przyczyn:
| Objawy | Potencjalna przyczyna |
|---|---|
| Wysoka liczba odczytów IO | Brak indeksów, skanowanie całych tabel |
| Długi czas wykonania zapytania | Nieefektywne JOINy, funkcje skalarne, brak filtracji |
| Przeciążenie CPU | Sortowania, agregacje, brak indeksów pokrywających |
| Blokady i deadlocki | Brak podziału operacji na partie, długie transakcje |
| Niestała wydajność zapytań | Problemy z parametryzacją i cache’owaniem planów |
Zidentyfikowanie konkretnego problemu wymaga analizy execution planu oraz danych z SET STATISTICS IO i SET STATISTICS TIME, co pozwala ustalić, które elementy zapytania są najbardziej kosztowne i wymagają optymalizacji. Jeśli chcesz pogłębić swoją wiedzę i nauczyć się praktycznego podejścia do analizy i optymalizacji zapytań, polecamy Kurs SQL Server - wykorzystanie języka SQL Server do pracy z danymi i raportami.
Techniki optymalizacji zapytań T-SQL
Optymalizacja zapytań T-SQL to proces polegający na usprawnieniu działania instrukcji SQL w celu zwiększenia wydajności systemu bazodanowego. Istnieje wiele podejść do poprawy efektywności zapytań, które można zastosować w zależności od charakterystyki danych, struktury tabel, indeksów oraz logiki biznesowej. Poniżej przedstawiamy najważniejsze techniki wykorzystywane w praktyce.
- Tworzenie i utrzymywanie indeksów – odpowiednio zaprojektowane indeksy mogą znacząco skrócić czas wykonywania zapytań, zwłaszcza przy operacjach filtrowania i łączenia tabel.
- Ograniczenie pobieranych danych – stosowanie klauzuli
SELECTz konkretnymi kolumnami zamiastSELECT *oraz dodawanie warunków wWHEREpozwala zmniejszyć ilość przesyłanych danych. - Optymalizacja operatorów JOIN – wybór odpowiedniego typu złączenia oraz kolejności tabel w zapisie może znacząco wpłynąć na koszt zapytania.
- Wykorzystywanie zmiennych tabelarycznych i tabel tymczasowych – ich odpowiednie zastosowanie pomaga w przechowywaniu danych pośrednich i redukcji złożoności zapytań.
- Unikanie funkcji skalarnych w filtrach – funkcje używane w klauzulach
WHERElubJOINmogą uniemożliwiać efektywne wykorzystanie indeksów. - Refaktoryzacja złożonych zapytań – rozbijanie długich instrukcji SQL na mniejsze, bardziej czytelne fragmenty może pomóc w identyfikacji nieefektywnych elementów wykonania.
- Prawidłowe typowanie danych – zgodność typów danych w porównywanych kolumnach i parametrach wpływa na możliwość wykorzystania indeksów oraz ogranicza konieczność konwersji typów w czasie wykonywania zapytania.
W poniższej tabeli zestawiono wybrane techniki wraz z ich podstawowym zastosowaniem:
| Technika | Zastosowanie |
|---|---|
| Tworzenie indeksów | Przyspieszenie wyszukiwania i sortowania danych |
| Unikanie SELECT * | Zmniejszenie ilości danych przesyłanych i analizowanych |
| Odpowiednie stosowanie JOIN | Efektywne łączenie danych z wielu tabel |
| Unikanie funkcji skalarnych w WHERE | Umożliwienie wykorzystania indeksów |
| Typowanie danych | Eliminacja niepotrzebnych konwersji i błędów wykonania |
Przykład nieoptymalnego zapytania:
SELECT * FROM Orders WHERE YEAR(OrderDate) = 2023
Lepsza wersja wykorzystująca zakres dat, umożliwiająca użycie indeksu na kolumnie OrderDate:
SELECT * FROM Orders
WHERE OrderDate >= '2023-01-01' AND OrderDate < '2024-01-01'
Stosowanie powyższych technik często prowadzi do znaczącej poprawy czasu wykonania zapytań i zmniejszenia obciążenia serwera SQL.
Narzędzia wspierające analizę wydajności w SQL Server
SQL Server oferuje szereg narzędzi, które pomagają w analizie i optymalizacji zapytań T-SQL. Znajomość ich możliwości pozwala skuteczniej diagnozować problemy z wydajnością oraz podejmować trafniejsze decyzje dotyczące ich rozwiązania. Poniżej przedstawiamy najważniejsze z nich i ich podstawowe zastosowania.
- SQL Server Management Studio (SSMS) – to główne środowisko pracy administratorów i deweloperów baz danych. Umożliwia generowanie graficznych planów wykonania, analizowanie statystyk IO/TIME, a także udostępnia wbudowane narzędzia, takie jak Query Store czy Activity Monitor.
- Query Store – rejestruje historię wykonania zapytań wraz z ich planami oraz metrykami wydajności. Ułatwia porównywanie różnych wersji planów i identyfikowanie regresji wydajności.
- Execution Plan Viewer – pozwala szczegółowo analizować plany wykonania zapytań, zarówno w formie graficznej, jak i tekstowej. Pomaga zrozumieć sposób, w jaki zapytanie jest realizowane przez silnik bazy danych.
- Dynamic Management Views (DMV) – zestaw widoków systemowych, które umożliwiają monitorowanie stanu serwera, statystyk zapytań oraz używanych planów wykonania. DMV są szczególnie przydatne do zaawansowanej diagnostyki w środowiskach produkcyjnych.
- SQL Server Profiler i Extended Events – narzędzia do śledzenia aktywności serwera w czasie rzeczywistym. Pozwalają rejestrować zdarzenia związane z wykonaniem zapytań, co ułatwia analizę problemów wydajnościowych i błędów.
- Database Tuning Advisor – służy do automatycznej analizy zapytań i rekomendowania indeksów, partycjonowania oraz innych strategii optymalizacyjnych. Może być pomocny przy bardziej złożonych analizach wydajności.
Dobór odpowiedniego narzędzia zależy od rodzaju problemu oraz etapu pracy nad zapytaniem – inne funkcjonalności będą przydatne podczas diagnozy, a inne w fazie monitorowania czy testowania wydajności.
Podsumowanie i najlepsze praktyki
Analiza wydajności zapytań T-SQL to proces wymagający zarówno znajomości mechanizmów działania silnika bazy danych, jak i umiejętności interpretowania narzędzi diagnostycznych takich jak execution plan oraz wyniki STATISTICS IO i STATISTICS TIME. Choć każde z tych narzędzi dostarcza innych informacji, razem umożliwiają skuteczną identyfikację i rozwiązywanie problemów z wydajnością zapytań.
Execution plan pozwala zrozumieć, w jaki sposób SQL Server przetwarza zapytanie – jakie operatory są wykorzystywane, w jakiej kolejności oraz jak przebiega dostęp do danych. Z kolei STATISTICS IO i TIME dostarczają miar ilościowych, takich jak liczba odczytanych stron danych czy czas wykonania poszczególnych etapów zapytania.
Aby skutecznie diagnozować problemy wydajnościowe, warto stosować kilka sprawdzonych praktyk:
- Regularnie analizuj plany wykonania – umożliwia to wykrycie nieoptymalnych operatorów i potencjalnych miejsc do optymalizacji.
- Monitoruj zużycie zasobów – dzięki STATISTICS IO i TIME można szybko oszacować koszt zapytania i porównać efektywność różnych wersji zapytań.
- Unikaj niepotrzebnej złożoności – prostsze zapytania są zazwyczaj bardziej czytelne i łatwiejsze do zoptymalizowania.
- Dbaj o aktualność statystyk i indeksów – mają one bezpośredni wpływ na wybór planu wykonania przez optymalizator zapytań.
- Testuj zmiany na realistycznych danych – pozwala to lepiej przewidzieć zachowanie zapytania w środowisku produkcyjnym.
Stosowanie powyższych zasad pozwala nie tylko na skuteczne diagnozowanie problemów, ale również na tworzenie zapytań, które od początku działają wydajnie i przewidywalnie w różnych warunkach. Jeśli chcesz poznać więcej takich przykładów, zapraszamy na szkolenia Cognity, gdzie rozwijamy ten temat w praktyce.
Majczęściej zadawane pytania i odpowiedzi odnośnie Debugowanie zapytań T-SQL: jak czytać execution plan i STATISTICS IO/TIME
Najlepiej zacząć od połączenia execution planu z wynikami STATISTICS IO i STATISTICS TIME. Taki zestaw pokazuje jednocześnie sposób wykonania zapytania oraz jego koszt w odczytach i czasie. W praktyce warto przejść przez trzy kroki:
- sprawdzić, które operatory dominują w planie,
- porównać liczbę odczytów logicznych i fizycznych,
- ocenić czas CPU oraz czas całkowity wykonania.
Najważniejsze jest używanie obu źródeł informacji razem. Execution plan pokazuje, jak SQL Server realizuje zapytanie i jakie operatory wybiera, a STATISTICS IO/TIME ujawniają rzeczywisty koszt wykonania. Sam plan nie zawsze wystarczy do oceny wpływu zapytania na zasoby, tak samo jak same statystyki nie wyjaśniają, skąd bierze się problem.
Sygnałem ostrzegawczym są operacje Scan zamiast Seek. Jeśli w planie często pojawia się Table Scan, Index Scan lub Clustered Index Scan, zapytanie może przetwarzać zbyt dużo danych. Warto wtedy sprawdzić warunki filtrowania, dobór kolumn oraz to, czy użyte konstrukcje nie utrudniają optymalizatorowi skorzystania z dostępnych indeksów.
Wysokie wartości w STATISTICS IO zwykle oznaczają, że zapytanie odczytuje więcej stron danych, niż powinno. To często wskazuje na pełne skanowanie tabel, brak odpowiednich indeksów albo nieefektywne filtrowanie. Szczególnie przydatne jest porównywanie odczytów między dwiema wersjami tego samego zapytania, bo pozwala szybko ocenić, która wersja mniej obciąża serwer.
Duża różnica między czasem CPU a czasem całkowitym może wskazywać, że zapytanie czeka na zasoby. Jeśli czas rzeczywisty jest wyraźnie większy niż czas procesora, problem nie zawsze leży w samej logice zapytania. Taki wynik może sugerować oczekiwanie na dysk, blokady albo inne ograniczenia środowiska wykonawczego.
Funkcje skalarne w WHERE mogą utrudniać wykorzystanie indeksów. Gdy warunek filtruje dane przez przekształcenie wartości kolumny, SQL Server częściej wybiera skanowanie zamiast bardziej selektywnego dostępu. W praktyce lepiej przepisać warunek tak, aby operował na zakresie wartości, jak w przykładzie z filtrowaniem po dacie bez użycia funkcji YEAR().
Na początku warto skupić się na operatorach dostępu do danych, złączeń i sortowania. To one najczęściej ujawniają źródło problemu wydajnościowego. Szczególną uwagę zwracają zwykle:
- Table Scan i Index Scan,
- Nested Loops, Hash Match i Merge Join,
- Sort oraz Aggregate.
Ich obecność należy zawsze ocenić w kontekście liczby przetwarzanych wierszy i kosztu operacji.
Najczęstszy błąd to poprawianie zapytania bez sprawdzenia planu wykonania i statystyk IO/TIME. Równie problematyczne bywa używanie SELECT *, funkcji skalarnych w filtrach, zbyt szerokich JOINów oraz brak ograniczenia liczby przetwarzanych danych. Często pomijany jest też wpływ typów danych, parametrów oraz aktualności statystyk i indeksów na wybór planu.