100% CPU w PrestaShop? Zanim dokupisz mocniejszy VPS, zrób to (Case Study)
###02Diagnoza z terminala
Większość właścicieli sklepów na platformie PrestaShop w momencie, gdy baza danych zaczyna generować wysokie zużycie procesora (CPU: 100%), decyduje się na bezrefleksyjne dokupienie mocniejszego VPS-a. To błąd rzemieślniczy.
Struktura bazy danych PrestaShop – ze względu na rozbicie cech produktów, atrybutów, kombinacji oraz multisklepowości na osobne relacje – z natury generuje potężne, wielopoziomowe zapytania JOIN. Jeśli baza nie posiada odpowiednich indeksów, każdy klient filtrujący produkty w sklepie zmusza silnik MariaDB do pełnego skanowania dysku (Full Table Scan).
Poniżej znajduje się zapis realnej ścieżki diagnostycznej i naprawczej na serwerze produkcyjnym, gdzie TTFB kategorii produktów wynosiło ponad 2.4 sekundy.
01 · Diagnoza z terminala (The Symptom)
Analiza za pomocą narzędzia htop wykazała permanentne wysokie utylizowanie wątków przez proces mariadbd. Pierwszym krokiem było uruchomienie logowania wolnych zapytań (Slow Query Log) bezpośrednio z poziomu CLI, aby namierzyć winowajcę.
Bash
# Włączenie logowania wolnych zapytań w locie (bez restartu usługi)
mysql -u root -p -e "SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1.0;"
Po kilkunastu minutach w logu /var/log/mysql/mariadb-slow.log pojawił się powtarzalny schemat – zapytanie generowane przez moduł warstwowego filtrowania (Faceted Search), które wykonywało się aż 1.82 sekundy:
SQL
# Time: 260615 14:22:11
# User@Host: prestadb[prestadb] @ localhost []
# Query_time: 1.824102 Lock_time: 0.000121 Rows_sent: 48 Rows_examined: 1420540
SELECT p.id_product, fp.id_feature_value
FROM ps_product p
LEFT JOIN ps_feature_product fp ON (p.id_product = fp.id_product)
LEFT JOIN ps_category_product cp ON (p.id_product = cp.id_product)
WHERE cp.id_category = 42 AND fp.id_feature = 5
ORDER BY p.id_product DESC LIMIT 48;
Zwróć uwagę na parametr Rows_examined: 1 420 540. Aby zwrócić zaledwie 48 produktów na stronę, MariaDB musiała przeszukać i porównać w pamięci ponad 1.4 miliona rekordów.
02 · Analiza struktury (The Explain)
Użycie klauzuli EXPLAIN przed zapytaniem natychmiast obnażyło brak optymalizacji po stronie bazy danych:
SQL
EXPLAIN SELECT p.id_product, fp.id_feature_value FROM ps_product p ...
| table | type | possible_keys | key | key_len | ref | rows | Extra |
| fp | ALL | PRIMARY | NULL | NULL | NULL | 842100 | Using where; Using temporary; Using filesort |
| p | eq_ref | PRIMARY | PRIMARY | 4 | fp.id_product | 1 | Using index |
| cp | ref | PRIMARY | PRIMARY | 4 | fp.id_product | 1 | Using where |
Kluczowy jest wiersz pierwszy: tabela ps_feature_product (fp) zwraca typ połączenia ALL (Full Table Scan), a pole key ma wartość NULL. Baza danych nie użyła żadnego indeksu dla tabeli łączącej produkty z ich cechami.
03 · Wdrożony Fix (The Solution)
PrestaShop domyślnie zakłada indeksy na klucze główne, ale bardzo często pomija indeksy kompozytowe (wielokolumnowe), które są niezbędne przy skomplikowanych operacjach JOIN z warunkami WHERE.
Rozwiązaniem było nałożenie indeksów na kolumny, po których następuje stałe mapowanie i filtrowanie danych:
SQL
-- Dodanie indeksu kompozytowego na tabelę cech produktów
ALTER TABLE ps_feature_product ADD INDEX idx_product_feature (id_product, id_feature);
-- Dodanie indeksu na tabelę kategorii (w celu przyspieszenia filtrowania wewnątrz kategorii)
ALTER TABLE ps_category_product ADD INDEX idx_category_product (id_category, id_product);
-- Wymuszenie odświeżenia statystyk optimizera MariaDB
ANALYZE TABLE ps_feature_product, ps_category_product, ps_product;
04 · Wynik liczbowy (Data-Driven Proof)
Po wdrożeniu zmian i ponownym wykonaniu testu EXPLAIN, typ połączenia zmienił się z ALL na ref / range, a baza danych zaczęła prawidłowo utylizować nowo utworzone klucze (idx_product_feature).
Plaintext
Przed optymalizacją:
● Rows examined: 1 420 540
● Czas wykonania zapytania SQL: 1.82 s
● Średni TTFB podstrony kategorii: 2420 ms
Po wdrożeniu indeksów:
● Rows examined: 214
● Czas wykonania zapytania SQL: 0.002 s
● Średni TTFB podstrony kategorii: 112 ms
Wnioski operacyjne: Narzut na procesor serwera spadł o 78%. Sklep odzyskał stabilność bez wydawania ani jednej złotówki na wyższy pakiet hostingowy czy mocniejszą maszynę w chmurze.
Plaintext
// koniec_logu
Zauważyłeś podobne symptomy? Jeśli Twój panel administracyjny PrestaShop ładuje się w nieskończoność, a klienci czekają sekundy na odświeżenie filtrów w sklepie – baza danych prawdopodobnie dławi się na nieoptymalnych zapytaniach.
[ → Prześlij parametry serwera do darmowego audytu zerowego ]