![]()
Spis treści:
- Indeksy w bazie danych
- Analiza slow logów bazy danych
- Analiza zapytań za pomocą EXPLAIN
- Oczyszczanie i optymalizacja tabel
- Podsumowanie
To kolejna część serii o przygotowaniu PrestaShop na Black Friday – po fundamentach aplikacji i porządkach w bazie modułów pora na warstwę, która wprost decyduje o szybkości wszystkiego: bazę MySQL/MariaDB. Baza danych obsługuje produkty, koszyki, promocje, rejestracje i płatności, więc każdy zbędny odczyt, brak indeksu czy przerośnięta tabela od razu podbija TTFB (ang. Time to First Byte) i obniża konwersję, szczególnie przy wielu równoległych akcjach w piku ruchu.
Jeśli kliknięcie „Dodaj do koszyka” trwa kilka sekund, część osób zwyczajnie zrezygnuje z zakupu i przejdzie do konkurencji – dlatego krok po kroku przejdziemy przez uzupełnianie indeksów w kluczowych tabelach, korzystanie z slow logów i EXPLAIN oraz bezpieczne czyszczenie rosnących tabel, tak aby baza działała przewidywalnie szybko pod obciążeniem w piku ruchu.
Po pierwszej części z serii powstała lista najwolniejszych zapytań, teraz zamienimy ją na konkretne działania: skrócimy czasy z sekund do milisekund dzięki celowanemu indeksowaniu, pracy na slow logach, użyciu EXPLAIN i higienie danych w „puchnących” tabelach.
Efekt biznesowy jest prosty: niższy TTFB na ścieżce karta produktu → koszyk → checkout, mniej porzuceń koszyka i większa odporność na skoki ruchu w Black Week.
Jak zoptymalizować bazę danych PrestaShop? Wyjaśniamy poniżej!
1. Indeksy w bazie danych
Indeksy to skrót dla bazy – pozwalają ominąć przeszukiwanie całej tabeli i przejść prosto do pasujących rekordów – w praktyce to najtańszy sposób na odczuwalne przyspieszenie SELECT‑ów w PrestaShop. Brak indeksu to brak „spisu treści” dla kolumn z WHERE/JOIN, więc silnik musi przeprowadzić pełny skan rekord po rekordzie, co przy setkach tysięcy lub milionach wierszy zmienia się w sekundy czekania, zwłaszcza w godzinach szczytu. Jednocześnie trzeba zadbać o równowagę: indeksy przyspieszają odczyt, ale spowalniają INSERT/UPDATE/DELETE – dodawaj je świadomie, na podstawie audytu i wolnych zapytań ze slow logów, a nie na wszelki wypadek.
Dlatego w codziennej pracy liczą się trzy rzeczy:
- Szybsze filtrowanie: indeks pomaga błyskawicznie znaleźć wiersze po kolumnach z WHERE lub JOIN, stabilizując czasy kategorii, karta produktu, koszyka i checkoutu.
- Unikanie pełnych skanów: bez indeksu silnik czyta wszystkie wiersze – im większa tabela, tym większa degradacja czasu odpowiedzi.
- Koszt przy zapisie: zbyt wiele indeksów spowalnia modyfikacje – lepiej mieć mniej, ale trafionych (czasem złożonych), niż indeksować wszystko.
Jak szybko sprawdzić indeksy
W większości tabel PrestaShop są natywnie sensowne indeksy, ale specyfika sklepu (niestandardowe pola do filtrowania, integracje, raporty) często wymagają dodatkowych. Najprościej zweryfikować je w panelu SQL/phpMyAdmin poleceniem: SHOW INDEX FROM table_name, a wynik porównać z kolumnami pojawiającymi się w najwolniejszych zapytaniach. Jeśli kolumna z WHERE/JOIN nie ma indeksu – zaplanuj jego dodanie i przetestuj na stagingu.

Lista indeksów w ps_customer – widać m.in. PRIMARY oraz customer_email.
Przykład praktyczny
Wyobraźmy sobie listę klientów wielkości sporego miasta (ps_customer). Gdy wyszukiwanie po e‑mailu nie ma indeksu, baza musi przejrzeć niemal każdą pozycję i robi się z tego kilka sekund. Po dodaniu indeksu baza wie, gdzie zajrzeć – różnica jak między kartkowaniem zeszytu a skokiem do wiersza w Excelu. Na realnym przykładzie z ps_customer (~600 tys. rekordów) SELECT po e-mailu z indeksem trwa ok. 1 ms (w praktyce natychmiast).

SELECT po email z indeksem – około 1 ms (odczyt natychmiastowy).

Ten sam SELECT bez indeksu – około 117 ms (pełny skan tabeli, ~100× wolniej).
2. Analiza slow logów bazy danych
Jeśli konkretne operacje bazy trwają za długo, włącz Slow Query Log w MySQL. To wbudowany rejestr, który zapisuje każde zapytanie przekraczające ustawiony próg (np. 0,5 s), dzięki czemu powstaje jasna lista: które SQL‑e są najwolniejsze i które występują najczęściej. Pozwala pracować na danych, a nie przeczuciach.
Co włączyć
- Poproś administratora lub skorzystaj z panelu hostingu, aby uruchomić rejestrowanie długich zapytań. Ustaw niski próg, np. 0,5 s, i skieruj log do pliku, który można łatwo pobrać i przejrzeć.
- Jeśli środowisko na to pozwala, włącz rejestrowanie zapytań niewykorzystujących indeksów – szybciej wychwycisz kolumny z WHERE/JOIN, które wymagają indeksu.
Czego szukać
- Zacznij od częstotliwości i czasu. Które zapytania najczęściej przekraczają próg? Czy powtarzają się te same SELECT‑y na dużych tabelach?
- Sprawdź, czy nie ma pełnych skanów. To one zwykle podbijają koszty przy dużych wolumenach danych.
Co dalej
- Uruchom EXPLAIN dla każdego wolnego zapytania z listy i sprawdź typ dostępu (np. ALL = pełny skan), użyte indeksy i szacowaną liczbę przetwarzanych wierszy.
- Najczęstsze przyczyny to: brak indeksu na kolumnie z WHERE/JOIN albo zbyt złożony plan (wiele JOIN‑ów bez zawężenia). Rozwiązanie: dodać brakujący (czasem złożony) indeks, uprościć zapytanie lub dołożyć warunki/LIMIT.
- Zawsze potwierdź efekt pomiarem „przed/po” w slow logu i w EXPLAIN – i zapisz wynik w backlogu (np. spadek z 800 ms do 40 ms).
Dlaczego warto robić to cyklicznie
Wraz ze wzrostem sklepu i pojawianiem się nowych modułów profil zapytań się zmienia. To, co było neutralne przy 200 wierszach, potrafi stać się wąskim gardłem przy setkach tysięcy. Dlatego monitoruj slow log okresowo (po wdrożeniach, przed kampaniami) i planuj indeksy proaktywnie. Jeśli wiadomo, że kolumna będzie używana do filtrowania lub łączenia tabel, dodaj indeks od razu, zamiast czekać na spadek wydajności w szczycie.
3. Analiza zapytań za pomocą EXPLAIN
EXPLAIN pokazuje, jak MySQL wykona zapytanie – czy użyje indeksu i ile wierszy przejrzy. Dzięki temu łatwo ocenić, czy zapytanie jest wspierane indeksem, czy wpada w pełny skan tabeli.
Co czytać w wyniku EXPLAIN
- Typ dostępu (kolumna type): wartości takie jak ALL, range, ref. ALL oznacza pełne skanowanie tabeli (sygnał do optymalizacji). range/ref zwykle wskazują użycie indeksu i znacznie mniejszy zakres danych.
- Użyty klucz (key): nazwa indeksu, z którego skorzysta optymalizator. NULL = brak użytego indeksu dla warunków zapytania.
- Liczba wierszy (rows): szacunkowa liczba rekordów do przejrzenia. Im wyższa, tym większy koszt i dłuższy czas.
- Extra: dodatkowe wskazówki, np. Using filesort lub Using temporary – informują o sortowaniu/tymczasowych tabelach, które często da się ograniczyć dobrym indeksem lub zmianą zapytania.

EXPLAIN bez indeksu na e-mail – type: ALL (pełny skan), key: NULL, rows: 567 936 – MySQL przeszukuje całą tabelę.

EXPLAIN z indeksem customer_email – type: ref, key: customer_email, rows: 1 – zapytanie trafia bezpośrednio do rekordu.
Wnioski
EXPLAIN to szybka weryfikacja czy indeks działa tak, jak zakładano. Idealnie nadaje się do analizy zapytań wyłapanych przez slow log: najpierw EXPLAIN ujawnia brak użytego indeksu lub pełny skan, potem dodanie właściwego (czasem złożonego) indeksu i ponowny EXPLAIN pokazuje, że typ dostępu spada do range/ref, a liczba rows maleje o rzędy wielkości. Tak potwierdza się skuteczność optymalizacji przed wdrożeniem na produkcję.
4. Oczyszczanie i optymalizacja tabel
Wraz z rozwojem sklepu niektóre tabele rosną szybciej niż reszta i zaczynają wpływać na czasy odpowiedzi. Dobra polityka retencji polega na regularnym usuwaniu danych zbędnych operacyjnie, przy jednoczesnym zachowaniu pełnej kopii zapasowej oraz testów na środowisku testowym. Kluczowa zasada: czyścić to, co nie jest potrzebne do działania koszyka, zamówień, płatności i rozliczeń, a pozostaw dane, które są wymagane biznesowo lub prawnie.
Szybkie porządki: tabele rosnące najszybciej
- connections, connections_page, connections_source: to logi wizyt i sesji – potrafią urosnąć do setek milionów rekordów, co obciąża odczyty i backupy. Bezpiecznie usuń stare wpisy (np. starsze niż kilka – kilkanaście dni) albo wprowadź cykliczną retencję z archiwizacją poza główną bazą.

ps_connections i tabele powiązane – dane sesji uruchamiają retencję – warto usuwać najstarsze wpisy cyklicznie.
- cart (+ powiązane): pracuj ostrożnie. Usuwaj tylko koszyki niezamknięte, wyraźnie przeterminowane (np. bez aktywności od X dni), aby nie kasować bieżących sesji. Przy porządku rozważ także powiązane wpisy w cart_product, customization/customized_data oraz address, ale wyłącznie wtedy, gdy są przypisane wyłącznie do tego porzuconego koszyka.
- guest: rekordy gości bez powiązań (np. bez koszyków/zamówień) można usuwać po określonym czasie, np. >30 dni, jeśli polityka prywatności i cele analityczne nie wymagają dłuższego przechowywania.
- statssearch: historia wyszukiwań służy analizie treści i UX – do bieżącej pracy zwykle wystarcza okno ostatnich tygodni. Starsze wpisy czyść lub eksportuj poza główną bazę.
- log: dziennik zdarzeń szybko puchnie i bywa odpytywany przy każdym zapisie (sprawdzanie duplikatów), a domyślnie brakuje mu indeksów pod często używane filtry. Regularnie usuwaj stare wpisy (np. >30 dni) i rozważ dodanie celowanych indeksów, jeśli log ma pozostać większym oknem czasu.
- mail: historia wysyłek nie jest krytyczna operacyjnie – ustaw retencję (np. 30 dni) i czyść cyklicznie, żeby nie obciążać backupów i zapytań administracyjnych.
- grupy cart_rule i powiązane: tabele z kuponami i regułami koszyka potrafią rosnąć lawinowo, zwłaszcza gdy moduły generują kody dynamicznie lub unikalne per użytkownik. Wprowadź comiesięczne czyszczenie wykorzystanych i przeterminowanych kodów wraz z rekordami w tabelach powiązanych (cart_rule_lang, cart_rule_carrier, cart_rule_group, cart_rule_country, cart_rule_shop, cart_rule_product_rule_group, cart_rule_product_rule, cart_rule_product_rule_value, cart_cart_rule), aby utrzymać spójność i ograniczyć koszty JOIN‑ów.
Dobre praktyki porządkowe
- Zanim usuniesz, sprawdź powiązania: czy rekord nie jest referencją w zamówieniach, płatnościach, dokumentach księgowych lub raportach.
- Najpierw archiwizacja: dla dłuższej analizy wynieś stare rekordy do magazynu danych (np. plik/inną bazę), a w produkcyjnej bazie zostaw krótsze okno operacyjne.
- Po czyszczeniu uruchom pomiary „przed/po” na krytycznych widokach (karta produktu/kategoria/koszyk/checkout) oraz sprawdź backupy i replikację, bo mniejsze tabele przyspieszają także operacje utrzymaniowe.
WAŻNE
Zabiegi porządkowe wykonuj najpierw na kopii bazy lub środowisku testowym. Zawsze zrób pełną kopię zapasową przed usuwaniem danych. Niewłaściwy skrypt czyszczący potrafi uszkodzić integralność bazy – testuj, zanim wdrożysz na produkcji.
Podsumowanie
Uporządkowaliśmy warstwę danych tak, aby działała szybko również pod obciążeniem Black Week. Po pierwsze, dodane i zweryfikowane zostały właściwe indeksy – dzięki nim SELECT‑y przeskakują z pełnych skanów do precyzyjnych odczytów, co skraca czasy z sekund do milisekund na ścieżkach karta produktu → koszyk → checkout. Po drugie, uruchomiona i wykorzystana została analiza slow logów oraz EXPLAIN: najpierw zebrana została lista realnie najdroższych zapytań, a następnie potwierdzono (na EXPLAIN), że wprowadzone indeksy i poprawki rzeczywiście zmieniają typ dostępu i liczbę przetwarzanych wierszy. Po trzecie, wprowadzona została polityka retencji danych – cykliczne czyszczenie tabel operacyjnego szumu (m.in. connections, logs, mail, przeterminowane koszyki i kody rabatowe) odciąża bazę, przyspiesza backupy i stabilizuje czasy odpowiedzi w piku.
Na koniec warto zrobić prosty test „przed/po”: porównać TTFB i czasy kluczowych widoków (karta produktu, kategorie, koszyk, checkout) oraz łączny czas i liczbę zapytań SQL na tych ścieżkach. To twardy dowód, że zmiany przyniosły efekt, a baza – dzięki indeksom, korektom zapytań i retencji – jest przygotowana na wzmożony ruch.
Co dalej?
W kolejnym artykule: PrestaShop na Black Friday: Konfiguracja serwera – przedstawimy praktyczne ustawienia PHP, MySQL/MariaDB i www, cache na poziomie serwera (opcache, Redis/Memcached), limity i timeouty pod realny ruch, a także wskazówki dla HTTP/2/3, kompresji i TLS. Celem będzie domknięcie układanki: po uporządkowanej aplikacji i bazie – serwer skonfigurowany tak, by bezpiecznie dowieźć ruch w Black Week.
Jeśli potrzebujesz wsparcia przy optymalizacji swojego sklepu na PrestaShop lub po prostu chcesz porozmawiać o rozwoju – skontaktuj się z nami.