Przejdź do treści

Dlaczego PrestaShop jest wolny — 12 przyczyn i jak je zdiagnozować

Mateusz Bartocha

  • PrestaShop
  • wydajność
  • optymalizacja
  • MySQL
  • Core Web Vitals

Wolny sklep obniża konwersję, pogarsza doświadczenie użytkownika i utrudnia dobre Core Web Vitals. Zanim wydasz pieniądze na „przyspieszacz”, warto wiedzieć, co spowalnia PrestaShop. Oto 12 najczęstszych przyczyn, które spotykamy w audytach, i sposób na zdiagnozowanie każdej z nich.

Najpierw ustal: backend czy front-end?

„Wolny sklep” może oznaczać wolne generowanie HTML przez serwer, wolne renderowanie strony w przeglądarce albo oba problemy naraz. Wysoki TTFB kieruje diagnostykę w stronę backendu — PHP, MySQL, infrastruktury i konfiguracji serwera. Dobry TTFB przy słabym LCP lub INP wskazuje raczej na front-end — obrazy, JavaScript, CSS i skrypty zewnętrzne. To rozróżnienie oszczędza godziny szukania nie tam, gdzie trzeba.

1. Nieodpowiedni hosting (wolny dysk, za mało RAM)

Jedna z częstszych i najbardziej niedocenianych przyczyn. Współdzielony hosting z wysokimi opóźnieniami dysku, restrykcyjnymi limitami CPU lub małą ilością pamięci może nie poradzić sobie ze sklepem generującym kosztowne zapytania i realny ruch. Sam typ dysku (SSD vs NVMe) ani liczba produktów jeszcze o tym nie przesądzają — liczą się opóźnienia dysku, losowe operacje we/wy (IOPS), obciążenie hosta i sąsiedzi na współdzielonym środowisku. Zbyt mały bufor InnoDB zwiększa liczbę odczytów z pamięci masowej i może pogarszać opóźnienia zapytań.

Jak zdiagnozować: zmierz TTFB (czas odpowiedzi serwera) wielokrotnie, z lokalizacji blisko serwera, osobno dla cache hit i cache miss oraz bez dodatkowych przekierowań. Pamiętaj, że publicznie mierzony TTFB zawiera też DNS, TCP/TLS, proxy/CDN i sieć — to nie jest czysty czas PHP/MySQL, więc mierz jak najbliżej origin, porównuj podobne strony (p50/p95), a czas samej aplikacji odczytaj z profilera lub APM. Nasz orientacyjny sygnał ostrzegawczy to ~600 ms na stronie kategorii — to praktyczny próg z audytów, nie standard; zależy od lokalizacji i architektury. Sprawdź też IOPS dysku i wysycenie CPU. Nie diagnozuj wyłącznie po „użyciu RAM” — Linux i MySQL celowo zajmują wolną pamięć na cache, więc samo wysokie użycie nie oznacza problemu.

2. Niezoptymalizowana baza MySQL

PrestaShop z czasem obrasta w dane: tabele ps_connections, ps_guest, ps_cart, logi i statystyki potrafią urosnąć do milionów wierszy. Warto sprawdzić też tabelę ps_configuration, ładowaną intensywnie przy obsłudze żądań: jej rozrost po dziesiątkach instalowanych i usuwanych modułów (osierocone wpisy) bywa źródłem narzutu, ale realny wpływ zależy od wersji i sposobu cache’owania — potwierdź go pomiarem, a wpisów nie usuwaj „w ciemno” (najpierw backup, bo ręczne czyszczenie potrafi uszkodzić moduły). Domyślny schemat ma indeksy, ale wraz z rozrostem tabel rośnie koszt tych zapytań, które skanują duże zakresy, sortują albo nie trafiają w odpowiedni indeks (typowo zapytania modułów) — nie wszystkie zapytania stają się przy tym proporcjonalnie wolniejsze.

  • Włącz slow query log, ale nie czytaj tylko najdłuższych pojedynczych wpisów — agreguj zapytania po wzorcu (fingerprint) i patrz na łączny koszt (np. pt-query-digest): zapytanie 50 ms wykonane 100 000 razy kosztuje więcej niż jedno 2-sekundowe.
  • Sprawdź rozmiar największych tabel — dane i indeksy razem (SELECT table_name, data_length + index_length ... FROM information_schema.tables ...), nie samo data_length.
  • Zweryfikuj konfigurację InnoDB (innodb_buffer_pool_size) względem dostępnej pamięci.
  • Szukaj typowych wzorców: brak indeksów w tabelach modułów, osobny SELECT dla każdego produktu (wzorzec N+1), kosztowne COUNT(*), duże sortowania i tabele tymczasowe, zapytania po kombinacjach i filtrach.

3. Źle skonfigurowany cache (OPcache, Smarty, obiektowy)

Bez OPcache PHP przy każdym żądaniu na nowo wczytuje i kompiluje kod. W PrestaShop upewnij się dodatkowo, że na produkcji wyłączone jest wymuszanie kompilacji szablonów Smarty (force compile) i działa cache skompilowanych szablonów. To jedna z pierwszych rzeczy do sprawdzenia — weryfikacja jest szybka, a błędna konfiguracja dotyczy całej aplikacji; bardzo często jest po prostu źle ustawiona.

Cache obiektów nie zawsze przyspiesza sklep. W panelu Zaawansowane → Wydajność (w PrestaShop 1.7/8/9) dostępne są zwykle APC (APCu na PHP 7+) oraz Memcached — dokładna lista zależy od wersji sklepu i zainstalowanych rozszerzeń PHP. Redis nie jest standardowym backendem cache obiektowego w panelu (rdzeń nie ma klasy CacheRedis) — wymaga dedykowanego modułu. Przy pojedynczym, szybkim serwerze dodatkowa warstwa może nie dać zauważalnego efektu, a przy złej konfiguracji nawet zwiększyć opóźnienia. Zyskuje na znaczeniu przy większym ruchu, kosztownych operacjach i środowisku wieloserwerowym. Najpierw zmierz skuteczność cache i profil zapytań, zanim go włączysz.

Jak zdiagnozować: sprawdź nie tylko, czy OPcache jest aktywny (opcache_get_status), ale też czy nie brakuje mu pamięci i miejsca na skrypty (opcache.memory_consumption, opcache.max_accelerated_files, liczba cached scripts, restarty z braku pamięci) oraz czy patrzysz na właściwe SAPI — PHP-FPM, nie CLI. Zweryfikuj też kompilację szablonów Smarty i katalog var/cache/prod. Backendu cache obiektów nie włączaj „na wszelki wypadek” — dobierz go do architektury i ruchu.

Wskazówka eksperta

open_basedir po cichu wyłącza realpath cache w PHP

Oto mniej znane ustawienie, które po cichu kosztuje wydajność. Wielu administratorów nie zdaje sobie sprawy, że włączenie restrykcji open_basedir w PHP wyłącza realpath cache — przy aktywnym open_basedir PHP faktycznie wymusza realpath_cache_size równe 0. Z wyłączonym cache PHP musi rozwiązywać ścieżki w systemie plików od zera dla tysięcy operacji include, require i operacji na plikach, które wykonuje każde żądanie PrestaShop, zamiast korzystać z zapamiętanego wyniku.

Na małej stronie jest to pomijalne. Na większym sklepie PrestaShop — głębokie drzewo katalogów, wiele modułów, duża automatycznie ładowana baza kodu — to powtarzane rozwiązywanie ścieżek (lawina wywołań systemowych lstat) staje się mierzalnym narzutem na każde żądanie. W poprawnie odizolowanym środowisku — dedykowany użytkownik PHP-FPM na sklep, właściwe uprawnienia plików, kontenery lub maszyny wirtualne — można wyłączyć open_basedir i zamiast tego odpowiednio dobrać realpath_cache_size (oraz realpath_cache_ttl), co może zauważalnie skrócić czas wykonania PHP.

W naszych audytach daje to zwykle około 5–20% skrócenia czasu wykonania PHP albo mniej więcej 50–200 ms niższy TTFB na części sklepów — to obserwacje z praktyki, nie gwarantowany wynik. To nie jest uniwersalna rekomendacja. Wyłączenie open_basedir na słabo odizolowanym hostingu współdzielonym może osłabić granicę bezpieczeństwa między stronami na tym samym serwerze, więc najpierw należy przejrzeć architekturę hostingu i potwierdzić właściwą izolację, zanim zmieni się to ustawienie. Jak przy każdej zmianie tutaj — zmierz czas PHP i TTFB przed i po; to dokładnie ten rodzaj ustawienia, który nasze audyty wydajności weryfikują i bezpiecznie wdrażają tam, gdzie pozwala na to środowisko.

4. Nadmiarowe i źle napisane moduły

Moduły to jedno z najczęstszych źródeł „ukrytego” obciążenia. Rozbudowane filtry, „ostatnio oglądane”, rekomendacje czy liczniki potrafią generować setki zapytań SQL na każdej stronie i ładować własne CSS/JS na całym sklepie.

Jak zdiagnozować: włącz profiler (ustaw _PS_DEBUG_PROFILING_ na true w config/defines.inc.php) wyłącznie w kontrolowanym środowisku — profiler ujawnia zapytania SQL, ścieżki i dane konfiguracyjne, więc nie zostawiaj go na publicznym stagingu ani produkcji. Zobacz liczbę zapytań SQL oraz czas ładowania per hook. Ważniejszy od samej liczby zapytań jest ich łączny czas, powtarzalność i koszt pod obciążeniem — moduł odpowiadający za dużą część czasu PHP albo wykonujący powtarzalne, skanujące zapytania to kandydat do optymalizacji, zamiany lub usunięcia (setki zapytań na jednej stronie to sygnał ostrzegawczy).

5. Crony, integracje i procesy w tle

Importy produktów, synchronizacja stanów magazynowych, integracje ERP i marketplace, generowanie miniatur, indeksowanie wyszukiwarki oraz masowe aktualizacje cen potrafią jednocześnie obciążyć PHP, MySQL i dysk. Sklep zwalnia wtedy tylko o określonych godzinach, więc jednorazowy audyt łatwo to przeoczy.

Jak zdiagnozować: porównaj godziny spowolnień z harmonogramem cronów, logami integracji i wykresami CPU, I/O oraz zapytań MySQL. Uruchamianie poza szczytem pomaga, ale nie jest uniwersalnym lekarstwem (sklepy wielorynkowe, ciągła synchronizacja stanów): ograniczaj współbieżność, dziel pracę na mniejsze partie, kolejkuj, dodaj idempotencję oraz retry z backoffem i zabezpiecz przed równoległym uruchomieniem kilku kopii tego samego procesu (lock).

6. Boty i nadmierny ruch automatyczny

Sklep może być szybki przy normalnym ruchu, a zwalniać przez porównywarki cen, boty AI, crawlery SEO, integracje marketplace i scrapery. Najbardziej kosztowne są adresy filtrów, wyszukiwarki, sortowań i kombinacji kategorii — każde wejście może generować ciężkie zapytania SQL.

Jak zdiagnozować: przeanalizuj access logi według IP, User-Agentów, liczby żądań i najczęstszych URL-i; sprawdź, czy boty uderzają w dynamiczne strony, API, wyszukiwarkę i nieskończone kombinacje filtrów. Zanim zaczniesz blokować, rozróżnij klasy ruchu (legalny crawler, partner biznesowy, integracja API, monitoring, złośliwy scraper) — każda wymaga innej reakcji: ustal, czy ruch jest potrzebny biznesowo, czy bot respektuje robots, czy korzysta z API, czy da się ograniczyć jego częstotliwość i czy ma stabilne IP lub uwierzytelnienie. Dopiero potem sięgaj po Cloudflare, rate limiting, reguły cache i poprawne zarządzanie indeksowaniem. Pamiętaj: robots.txt nie jest zabezpieczeniem — uczciwe boty go respektują, złośliwe nie muszą.

7. Ciężki front-end (obrazy, render-blocking CSS/JS)

Duże, nieskompresowane obrazy i skrypty blokujące renderowanie psują Core Web Vitals — zwłaszcza LCP (czas wyrenderowania największego elementu) i INP (reakcja na interakcję). To bezpośrednio wpływa na odczuwaną szybkość, a Core Web Vitals są jednym z wielu sygnałów uwzględnianych przez systemy Google.

  • Jak zdiagnozować: zmierz stronę w PageSpeed Insights, ale rozdziel dane laboratoryjne (Lighthouse: TBT, kandydat na LCP, zasoby blokujące render) od danych polowych z CrUX (pomiary realnych użytkowników Chrome: LCP, INP, CLS). INP oceniaj z danych polowych — laboratoryjny przebieg bez realnych interakcji go nie zmierzy, a TBT jest tylko jego przybliżeniem.
  • Naprawa: najpierw ustal faktyczny element LCP (bywa nim tekst, nie obraz). Skonwertuj obrazy do WebP/AVIF i włącz lazy loading tylko poniżej pierwszego ekranu — obrazu, który jest elementem LCP, nie ładuj leniwie i rozważ dla niego selektywnie fetchpriority="high". Jawne width/height głównie ograniczają CLS, a nie przyspieszają LCP.
  • Naprawa: odrocz i ogranicz zbędny JavaScript oraz zewnętrzne widgety i skrypty marketingowe (kluczowe dla INP); dodaj font-display do fontów. Dobór napraw zależy od waterfalla zasobów i rzeczywistego elementu LCP — to nie jest automatyczny zestaw do włączenia w całości.

web.dev: Interaction to Next Paint (INP) — pomiar lab vs pole

8. Brak skutecznego cache HTTP, kompresji i (przy ruchu międzynarodowym) CDN

Dla sklepu obsługującego głównie jeden rynek, z serwerem w pobliskim regionie, ważniejsze od CDN bywają dobre nagłówki cache, HTTP/2 lub HTTP/3, szybki origin i ograniczenie liczby zasobów. Zysk opóźnieniowy z CDN jest zwykle większy przy użytkownikach oddalonych od origin, ale CDN odciąża i chroni serwer (cache, absorpcja skoków ruchu, terminacja TLS, filtrowanie botów) także przy ruchu krajowym. Kompresja (Brotli/gzip) mocno zmniejsza transfer plików tekstowych — HTML, CSS, JS, JSON, SVG; formaty już skompresowane (JPEG, WebP, AVIF, PNG, WOFF2) skorzystają na niej niewiele.

Jak zdiagnozować: sprawdź osobno cacheability i nagłówki (Cache-Control, wersjonowanie assetów), kompresję (Content-Encoding), transfer i czas pobierania zasobów statycznych z różnych lokalizacji.

Praktyczna wskazówka: w wielu sklepach najprostszym sposobem na odciążenie serwera jest wpięcie Cloudflare. Już plan Free daje globalny CDN, kompresję, HTTP/3, cache statyki i podstawowe filtrowanie botów. Sama instalacja nie naprawi wolnego kodu ani bazy, ale często wartościowo uzupełnia optymalizację infrastruktury — co daje, gdzie ma granice i jakich błędów unikać, opisujemy w osobnym artykule.

Czytaj: Cloudflare dla PrestaShop — korzyści i granice

9. Wyczerpana pula procesów PHP-FPM

Każde dynamiczne żądanie PrestaShop zajmuje jeden proces PHP-FPM. Gdy wszystkie procesy są zajęte, kolejne żądania czekają w kolejce — nawet jeśli serwer nie wykorzystuje całego CPU ani RAM — więc sklep zwalnia lub zwraca 502/504, choć wygląda na bezczynny. Warto spojrzeć na to trzeźwo: to zwykle objaw, nie przyczyna źródłowa. Pula zapełnia się, bo coś spowalnia żądania, a tym czymś jest zwykle jedna z opisanych już przyczyn — wolny SQL, kosztowne moduły, boty, zewnętrzne API lub crony. Osiągnięcie limitu pm.max_children to tylko dowód, że procesy są zajęte; nie mówi, dlaczego.

Dlatego zwiększanie pm.max_children bez znalezienia przyczyny źródłowej zwykle tylko ukrywa problem — a bywa, że go pogłębia, bo więcej równoległych procesów to więcej zużytej pamięci i większe równoległe obciążenie MySQL. Zanim ruszysz pulę, zestaw sygnały: komunikat „server reached pm.max_children” i status puli (aktywne procesy, długość kolejki nasłuchu, licznik osiągnięć max_children), PHP-FPM slowlog (request_slowlog_timeout), czas żądań, aktywność MySQL (Threads_running), wywołania zewnętrznych API, ruch botów i harmonogram cronów. Dopiero gdy wiesz, co zajmuje procesy, dobieraj rozmiar puli — i nigdy nie zwiększaj pm.max_children bez policzenia zużycia pamięci pojedynczego procesu, bo ryzykujesz swap i ubicie procesów przez OOM Killer.

10. Tryb debug i profiler włączone na produkcji

Pozostawiony po wdrożeniu tryb debug (_PS_MODE_DEV_) uruchamia dodatkową diagnostykę, szczegółowe raportowanie błędów i mechanizmy środowiska deweloperskiego, co potrafi znacząco zwiększyć czas i zużycie pamięci każdego żądania. Profiler (_PS_DEBUG_PROFILING_) dokłada osobny, duży narzut pomiaru na froncie i w back-office. To częsty, banalny, a bardzo kosztowny błąd.

Jak zdiagnozować: zweryfikuj _PS_MODE_DEV_ i _PS_DEBUG_PROFILING_ w config/defines.inc.php (oraz config/defines_custom.inc.php, jeśli istnieje — ustawiane w nim wartości mają pierwszeństwo). Na produkcji oba muszą być wyłączone.

11. Stara wersja PrestaShop i PHP

Niewspierane, starsze wersje PHP to nie tylko ryzyko bezpieczeństwa — to również brak wielu usprawnień wydajnościowych z nowszych wydań. Rzeczywisty zysk zależy jednak od kodu sklepu, modułów i konfiguracji OPcache. Uwaga: wersja PHP jest sprzężona z wersją PrestaShop (starsze PrestaShop nie działa na najnowszym PHP), więc podniesienie PHP zwykle wymaga skoordynowanego upgrade’u PrestaShop i modułów — to projekt, nie przełączenie flagi.

Jak zdiagnozować: sprawdź wersję PHP (php -v) i PrestaShop w back-office, a następnie zweryfikuj, jakie PHP wspiera Twoja wersja PrestaShop. Nie aktualizuj PHP bez testów kompatybilności motywu, override’ów i modułów. Nowsze PHP może poprawić wydajność, ale efekt trzeba zmierzyć na danym sklepie — czasem dominującym problemem pozostaje SQL, API lub moduł.

12. Rozrośnięty plik .htaccess (tysiące przekierowań)

Apache czyta plik .htaccess i rekompiluje reguły RewriteRule przy każdym żądaniu (inaczej niż w konfiguracji vhosta, gdzie reguły kompilują się raz i są cache’owane). Jeśli ktoś wrzucił do .htaccess tysiące niezoptymalizowanych przekierowań 301 — po migracji adresów URL albo z modułu SEO — każde żądanie przechodzi sekwencyjnie przez setki wyrażeń regularnych. To bezpośrednio podnosi TTFB, czyli czas odpowiedzi serwera.

Jak zdiagnozować: sprawdź rozmiar i liczbę reguł w .htaccess (ile linii RewriteRule/Redirect) — sama liczba to jednak tylko wskaźnik; znaczenie mają też kolejność reguł, backtracking, liczba RewriteCond i częstotliwość dopasowań, więc problem potwierdź pomiarem (porównaj TTFB z pełnym i z odchudzonym .htaccess). Rozwiązanie: przenieś stałe reguły do konfiguracji serwera (vhost), gdzie kompilują się raz, a masowe przekierowania obsłuż wydajniej — mapą przekierowań na poziomie serwera zamiast tysiąca linii regex. Uwaga: na hostingu współdzielonym lub w Plesku dostęp do vhosta bywa niemożliwy — wtedy przynajmniej ogranicz i uprość reguły. Prostsze Redirect (mod_alias) bywają tańsze od złożonych RewriteRule, gdy nie potrzeba przepisywania, ale mają inną semantykę (query stringi, kolejność) — zweryfikuj ją przed zamianą.

Apache: kiedy (nie) używać plików .htaccess

Podsumowanie: mierz, nie zgaduj — także pod obciążeniem

Zwykle spowolnienie to nie jedna przyczyna, lecz kilka naraz. Pierwszy krok to zawsze audyt: pomiar TTFB (osobno dla zimnego i rozgrzanego cache — pierwsze wejście po wyczyszczeniu cache bywa znacznie wolniejsze), analiza slow query log, profiling PHP i test hostingu. Dopiero dane pokazują, co naprawić najpierw, żeby uzyskać największy efekt najmniejszym nakładem. Przy trudniejszych, wielowarstwowych przypadkach pomaga APM lub profiling transakcyjny (np. Blackfire, Tideways, New Relic, Datadog, OpenTelemetry), który wiąże pojedyncze żądanie z kontrolerem, modułem, SQL-em i zewnętrznym API.

Pojedynczy test nie pokazuje, jak sklep zachowuje się pod obciążeniem — PrestaShop może odpowiadać w 300 ms przy jednym żądaniu, a zwolnić do kilku sekund w trakcie kampanii lub najazdu botów. Wykonaj kontrolowany test obciążeniowy — najlepiej na środowisku odzwierciedlającym produkcję albo w uzgodnionym oknie, na bezpiecznych endpointach i z limitem ruchu, bo test potrafi przeciążyć sklep, wysłać maile, tworzyć koszyki, odpalić integracje i uruchomić WAF. Do realistycznych scenariuszy użyj k6 lub podobnego narzędzia obsługującego sekwencje, cookie i wiele endpointów (ab traktuj tylko jako prosty test pojedynczego URL-a). Obserwuj jednocześnie CPU, I/O wait, load average, kolejkę PHP-FPM, Threads_running w MySQL, przepustowość (RPS) i odsetek błędów (timeouty, 429, 5xx) oraz p95/p99 czasu odpowiedzi, nie samą średnią. Nie oceniaj też sklepu po jednym teście Lighthouse — porównaj dane laboratoryjne z Core Web Vitals rzeczywistych użytkowników (CrUX) i z pomiarami serwera.

Często zadawane pytania

Jak szybko powinien ładować się sklep PrestaShop?

LCP poniżej 2,5 s na urządzeniach mobilnych to próg „dobry” Core Web Vitals. Dla TTFB celujemy w ~400 ms — to zaostrzony cel własny, ostrzejszy niż orientacyjne ~800 ms z web.dev. Powyżej tych wartości rośnie współczynnik odrzuceń, a słabe Core Web Vitals mogą obniżać pozycję w Google. Konkretne progi zależą od strony (główna, kategoria, produkt) i od ruchu.

Czy da się przyspieszyć PrestaShop bez zmiany hostingu?

Często tak — OPcache, poprawne ustawienie kompilacji Smarty, optymalizacja zapytań i front-endu (a w uzasadnionych przypadkach Redis lub Memcached) potrafią dać duży zysk na tym samym serwerze. Ale jeśli hosting jest wąskim gardłem (wysokie opóźnienia dysku, limity CPU, za mało pamięci), sama optymalizacja aplikacji nie wystarczy i migracja się zwraca.

Od czego zacząć diagnozę wolnego sklepu?

Od pomiaru, nie od zgadywania: TTFB, slow query log, profiling PrestaShop i PageSpeed Insights. Te cztery źródła zwykle wskazują 2–3 przyczyny odpowiedzialne za większość spowolnienia.

Nie wiesz, co spowalnia Twój sklep?

Wyślij adres sklepu, a otrzymasz wstępną ocenę wydajności — dowiesz się, co warto sprawdzić najpierw i jaki może być zakres prac.