W pewnym momencie każdy, kto pracuje z bazami danych, trafia na ścianę: zapytanie, które „zawsze działało”, nagle zaczyna mielić. A potem dochodzi kolejny raport, kolejne filtry, więcej danych i… jest źle. Optymalizacja SQL nie musi być magią. To w dużej mierze zestaw powtarzalnych kroków: zrozumienie planu wykonania, indeksów i tego, co naprawdę kosztuje. 1) Zanim zoptymalizujesz: zdefiniuj cel Czy chodzi o: skrócenie czasu odpowiedzi z 5 s do 200 ms? zmniejszenie obciążenia CPU? ograniczenie liczby odczytów z dysku? poprawę stabilności przy wielu użytkownikach? Bez celu łatwo zrobić „optymalizację”, która poprawi jeden scenariusz, a pogorszy inny. 2) Plan wykonania to mapa Pierwszy odruch: patrz na EXPLAIN (lub jego odpowiednik). Szukasz: pełnych skanów tabel (full scan), kosztownych sortowań, joinów wykonywanych w niekorzystnej kolejności, filtrów, które nie korzystają z indeksów. Plan nie mówi „jak napisać lepiej”, ale pokazuje, co silnik faktycznie robi, a to jest klucz. 3) Indeksy: mniej znaczy czasem więcej Indeks potrafi przyspieszyć zapytanie dramatycznie, ale: każdy indeks spowalnia INSERT/UPDATE/DELETE, zbyt wiele indeksów utrudnia optymalizatorowi wybór, indeks musi pasować do wzorca zapytania. Praktyczne zasady: indeksuj kolumny w WHERE / JOIN, które często filtrujesz, uważaj na indeksy na kolumnach o niskiej selektywności (np. „status” z 3 wartościami), rozważ indeksy złożone, ale w odpowiedniej kolejności (najpierw najbardziej selektywna / najczęściej filtrowana). blog dla zaawansowanych Pisanie zapytań „pod indeks” Częsty błąd: funkcja na kolumnie w WHERE, np. WHERE DATE(created_at) = .... To potrafi zabić użycie indeksu. Zamiast tego: filtruj zakresami (od–do), unikaj niepotrzebnych konwersji typów, dbaj o zgodność kolacji/typów w joinach. Jeśli musisz użyć funkcji, czasem pomaga kolumna pomocnicza (np. created_date) albo indeks funkcyjny (jeśli DB wspiera). 5) JOINy: nie wszystko trzeba łączyć od razu Kiedy zapytanie łączy 6 tabel, a potem filtruje po warunku, który zostawia 1% wierszy, spróbuj: najpierw zawęzić wynik w podzapytaniu/CTE, dołączać kolejne tabele dopiero po redukcji danych, upewnić się, że klucze joinów są indeksowane. Zasada: im wcześniej ograniczysz liczbę wierszy, tym mniej pracy dla silnika. 6) LIMIT nie zawsze ratuje LIMIT pomaga, ale nie „magicznie”. Jeśli DB musi posortować milion rekordów, żeby wybrać pierwsze 20, to LIMIT nie rozwiązuje problemu. Wtedy: indeks pod ORDER BY, zmiana strategii paginacji (keyset pagination zamiast OFFSET), preagregacje. 7) Agregacje i raporty: myśl hurtowo Raporty lubią mielić. Jeśli często liczysz te same rzeczy: materializuj widoki (jeśli to ma sens), licz przyrostowo, trzymaj tabele faktów i wymiary w czytelnym modelu. Na koniec: optymalizacja to proces Najlepsza praktyka to cykl: zmierz → zmień → zmierz. Nie zgaduj. Patrz w plan, logi i metryki. Wydajność w SQL rośnie najszybciej wtedy, gdy wiesz, co dokładnie kosztuje.