Produktseiten laden langsam, der Checkout ruckelt, die Bestellliste im Backend lädt nicht mehr richtig – in neun von zehn Fällen liegt die Ursache in der Datenbank, nicht in PHP. Bei stark frequentierten Shops ist es vorhersehbar, wo sich die Probleme konzentrieren: Langsame SQL-Abfragen in PrestaShop betreffen hauptsächlich vier Tabellen, die täglich neue Zeilen hinzufügen und keine löschen: ps_cart, ps_cart_product, ps_orders und ps_order_detail. Mit vier Schritten finden Sie diese Tabellen: Aktivieren Sie das Protokoll für langsame Abfragen, sortieren Sie die Einträge nach Gesamtdauer, führen Sie EXPLAIN für die problematischsten Einträge aus und ändern Sie anschließend die Abfrage oder den Index. Kein Rätselraten mehr! Jeder der folgenden Abschnitte beschreibt einen dieser Schritte und die Muster, die Warenkorb- und Bestelldaten am stärksten beeinträchtigen.

1.0 Warum Warenkorb- und Bestelltische zum größten Engpass werden
Ihr Katalog ändert sich kaum. Einmal indexiert, verhält er sich nahezu gleich, egal ob Sie 1,000 oder 50,000 Artikel verkaufen. Warenkorb- und Bestelldaten verhalten sich völlig anders, da sie stetig wachsen.
Mit zunehmendem Verkehr häufen sich vier Probleme:
- Reihen, die niemals verschwinden. Nahezu jeder Besucher, der den Warenkorb berührt, erhält einen Eintrag in ps_cart, Bots eingeschlossen. Diese Einträge verfallen nicht automatisch, sodass ps_cart und ps_cart_product auch lange nach dem Ende der Sitzung weiter ansteigen.
- Indizes, die in die falsche Richtung zeigen. Die Kernschlüssel bevorzugen Suchvorgänge anhand von id_cart oder id_order, während Berichte, Module und Admin-Filter eher nach Produkt, Datumsbereich oder Status suchen.
- Schleifen statt Mengen. Warenkorbregeln, Werbeaktionen und unachtsame Modul-Hooks verarbeiten jeweils nur einen Artikel, wodurch aus einem einzigen Seitenaufruf Dutzende von Hin- und Rückwegen werden.
- Auch der Backoffice-Bereich reiht sich in diese Ausweitung ein. Bestellbildschirme verknüpfen Kunden, Bestellstaaten, Spediteure, Länder und Geschäfte und sortieren und paginieren anschließend die Ergebnisse.
Checkout- und Administrationsseiten stoßen daher eher an ihre Grenzen als der Katalog. Nutzen Sie das als Indiz. Schnellzugriffe auf Produktseiten neben einer sich ständig aktualisierenden Bestellliste verweisen direkt auf Warenkorb und Bestellübersicht.
2.0 Beginnen Sie mit dem PrestaShop-Protokoll für langsame Abfragen.
Beginnen Sie hier. Das Protokoll zeigt an, was Ihr Server tatsächlich unter Live-Traffic ausgeführt hat, nicht was Sie vermuten, und kein anderes Tool bietet Ihnen diese Information kostenlos.

3.0 Wählen Sie einen Schwellenwert, der zu einem Geschäft passt.
Standardmäßig liegt die Abfragezeit für „long_query_time“ bei 10 Sekunden. Für den Einzelhandel ist dieser Wert irrelevant. Eine Warenkorbabfrage, die 900 ms dauert, bleibt unbemerkt, kostet Sie aber stillschweigend Conversions. Reduzieren Sie diesen Wert und erfassen Sie dabei auch indexlose Abfragen.
# Beispielhafte my.cnf-Einstellungen – vor der Anwendung in der Nähe der Produktionsumgebung optimieren.
[Mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/shop-slow-queries.log
long_query_time = 0.5
log_queries_not_using_indexes = 1
min_examined_row_limit = 1000
log_slow_admin_statements = 1
Beginnen Sie mit 0.5 Sekunden. Reduzieren Sie den Wert auf 0.1 Sekunden, nachdem Sie die offensichtlichen Fehlerquellen beseitigt haben. Beachten Sie einen Nebeneffekt: `log_queries_not_using_indexes` erfasst auch triviale Lesezugriffe auf Konfigurationstabellen, und `min_examined_row_limit` sorgt dafür, dass die Datei lesbar bleibt, sobald dies der Fall ist.
Änderungen zur Laufzeit funktionieren auch, allerdings mit einer Einschränkung. `long_query_time` gilt für neue Verbindungen, daher behalten PHP-FPM-Worker, die auf persistenten Verbindungen laufen, den alten Schwellenwert bei, bis sie neu gestartet werden. Die Dokumentation zum MySQL-Log für langsame Abfragen listet alle zugehörigen Variablen auf.
-- Laufzeitaktivierung. Betrifft nur neue Verbindungen.
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 0.5;
Nutzen Sie MariaDB, wie viele PrestaShop-Hoster? Dann fügen Sie `log_slow_verbosity = query_plan,explain` hinzu. Dadurch wird jeder Eintrag mit seinem Abfrageplan übermittelt, was Ihnen eine spätere Analyse erspart.
4.0 Die Rohdaten in eine Rangliste umwandeln
Rohprotokolle sind in großen Mengen unbrauchbar, daher sollten sie anhand des Abfrage-Fingerabdrucks aggregiert werden. mysqldumpslow ist in MySQL enthalten und muss nicht installiert werden.
mysqldumpslow -st -t 20 /var/log/mysql/shop-slow-queries.log # sortiert nach Gesamtzeit
mysqldumpslow -sc -t 20 /var/log/mysql/shop-slow-queries.log # sortiert nach Aufrufanzahl
Percona Toolkits pt-query-digest erledigt die Aufgabe einwandfrei. Literalwerte werden zu Fingerabdrücken zusammengefasst, Einträge nach Gesamtzeit sortiert, und jeder Eintrag enthält die geprüften Zeilen im Vergleich zu den zurückgegebenen Zeilen. Beachten Sie dieses letzte Paar. Nichts anderes deutet so deutlich auf einen fehlenden Index hin.
Hier liegt der Fehler, den Teams machen: Lesen Sie den Bericht anhand der Gesamtzeit und nicht anhand des Worst-Case-Szenarios. Ein dreisekündiger Bericht, der zweimal täglich ausgeführt wird, ist deutlich günstiger als eine 90 ms lange Warenkorbabfrage, die vierzig Mal pro Checkout ausgeführt wird. Trotzdem wird die kritisch wirkende Abfrage behoben, während die teure weiterhin besteht.
Das Log hat eine Schwachstelle. Eine Flut einzelner, kurzer Abfragen überschreitet nie den Wert von `long_query_time`, sodass nichts protokolliert wird. Diese lassen sich stattdessen mit dem Debug-Profiling von PrestaShop in einer Testumgebung erfassen: `_PS_DEBUG_PROFILING_` gibt ein Panel mit der Abfrageanzahl für jede Seite aus. Hunderte von Abfragen auf einer Warenkorbseite deuten auf eine Endlosschleife hin. Es bedeutet nicht, dass eine einzelne Anweisung langsam ist.
5.0 Lesen Sie den Plan mit MySQL EXPLAIN
Mit der Auswahlliste fragen Sie den Optimierer, was er vorhat. Er gibt lediglich Schätzungen mit EXPLAIN aus. Die Anweisung wird nie ausgeführt, weshalb die Ausführung in der Produktionsumgebung unbedenklich ist.

ERKLÄREN
SELECT o.id_order, o.reference, o.total_paid, c.lastname
FROM ps_orders o
JOIN ps_customer c ON c.id_customer = o.id_customer
WHERE o.date_add >= '2026-01-01 00:00:00'
UND o.current_state = 3
ORDER BY o.date_add DESC
GRENZE 50;
Vier Spalten enthalten den größten Teil der Bedeutung:
- tippe – die Zugriffsmethode. const, eq_ref und ref sind zulässig. range und index sind ebenfalls akzeptabel. ALL bedeutet einen vollständigen Tabellenscan, und bei großen ps_orders ist dies üblicherweise der gefundene Wert.
- Haupt – der tatsächlich gewählte Index. Wenn possible_keys Kandidaten auflistet, key aber NULL ist, wurden diese vom Optimierer verworfen, häufig weil eine Funktion die gefilterte Spalte umschließt.
- Zeilen und gefiltert – Das geschätzte Datenvolumen, das MySQL verarbeiten muss. Ein hoher Wert für die Zeilenanzahl in Kombination mit einem niedrigen Filterprozentsatz bedeutet, dass die Abfrage deutlich mehr Daten liest, als sie zurückgibt.
- Extra – die Warnungen. Die Verwendung von filesort und temporären Indizes bedeutet, dass kein Index die Sortierung erfüllt. Die Verwendung eines Index ist der optimale Fall: Ein abdeckender Index beantwortet die Abfrage, ohne die Tabelle zu verändern.
Die MySQL EXPLAIN-Referenz dokumentiert jeden Wert, und PlanetScales Leitfaden zum Lesen der EXPLAIN-Ausgabe bietet ein nützliches mentales Modell: Behandeln Sie Zugriffstypen wie eine Ampel und bearbeiten Sie zuerst die roten.
6.0 Wo EXPLAIN ANALYZE seinen Platz verdient
Ab Version 8.0.18 steht Ihnen außerdem EXPLAIN ANALYZE zur Verfügung. Diese Variante führt Ihre Abfrage aus und gibt neben den Schätzungen die gemessenen Laufzeiten und Schleifendurchläufe aus. Dies ist besonders hilfreich, wenn der Ausführungsplan gut aussieht, die Abfrage aber dennoch sehr langsam ist. Beachten Sie jedoch, dass diese Funktion ausgeführt wird. Verwenden Sie sie daher nur für schreibgeschützte SELECT-Abfragen außerhalb der Stoßzeiten.
MariaDB bietet mit ANALYZE SELECT eine ähnliche Funktion, die die tatsächlichen Zeilenanzahlen neben den vorhergesagten anzeigt. Eine große Diskrepanz zwischen den beiden Werten deutet in der Regel auf veraltete Statistiken hin. Führen Sie ANALYZE TABLE aus, überprüfen Sie die Ergebnisse erneut und entscheiden Sie anschließend über den Index.
7.0 Häufige Muster langsamer Abfragen in Warenkorb- und Bestelldaten
Vier Muster decken nahezu alles ab, was hier auftaucht. Jedes erfordert eine eigene Behandlungsmethode; finden Sie also heraus, welches Muster Sie in Händen halten, bevor Sie das Schema berühren.
7.1 Produktseitige Suchvorgänge scannen ps_cart_product
Prüfen Sie Ihr Schema, bevor Sie irgendwelche Annahmen treffen, da aktualisierte Installationen oft von Neuinstallationen abweichen:
SHOW CREATE TABLE ps_cart_product;
SHOW INDEX FROM ps_cart_product;
Im aktuellen Schema ist der Primärschlüssel von ps_cart_product mit id_cart verknüpft. Lesezugriffe auf den Warenkorb erfolgen daher bereits als Indexzugriffe, und das Hinzufügen eines weiteren Index (id_cart, id_product) führt lediglich zu langsameren Schreibvorgängen.

Das Problem beginnt in umgekehrter Richtung. MySQL liest einen Index von der ersten Spalte aus, daher kann ein Schlüssel, der mit „id_cart“ beginnt, keine Abfrage bedienen, die nur nach „id_product“ filtert. Tools zur Wiederherstellung abgebrochener Warenkörbe, Widgets zur Bestandsüberwachung und Massenproduktlöschungen filtern genau so und durchsuchen letztendlich die gesamte Tabelle.
-- Durchsucht ps_cart_product, wenn kein Index mit der Spalte "product" vorhanden ist.
SELECT COUNT(DISTINCT cp.id_cart)
FROM ps_cart_product cp
JOIN ps_cart c ON c.id_cart = cp.id_cart
WHERE cp.id_product = 4821
UND c.date_upd > DATE_SUB(NOW(), INTERVAL 7 DAY);
Die Optimierung der Warenkorbtabelle in PrestaShop hängt genau von dieser Unterscheidung ab. Indexieren Sie nur das, was Ihre Module tatsächlich abfragen, und lassen Sie alles, was der Kern bereits verarbeitet, unverändert.
7.2 Warenkorbregeln lösen N+1-Abfrageschleifen aus
Die Logik für Werbeaktionen verarbeitet Regeln nacheinander. PrestaShop sammelt die relevanten Warenkorbregeln, berechnet jeden Wert einzeln und prüft bei jeder Auswertung die eigenen Einschränkungen anhand von Produkt-, Kategorie-, Versanddienstleister-, Gruppen- und Ländertabellen. Zehn aktive Regeln erfordern daher zehn Auswertungen zuzüglich ihrer verschachtelten Abfragen – und zwar bei jedem Rendern des Warenkorbs und jeder Aktualisierung per AJAX.
Jede Abfrage bleibt schnell, sodass sie im Protokoll für langsame Abfragen nicht erfasst wird. Der Profiler zeigt stattdessen das Muster an: Die Anzahl der Abfragen steigt proportional zur Anzahl der aktiven Regeln.
Beheben Sie das Problem an der Quelle, anstatt mit Indizes zu arbeiten. Deaktivieren Sie abgelaufene Regeln, anstatt sie mit einem vergangenen Ablaufdatum aktiviert zu lassen, führen Sie sich überschneidende Werbeaktionen zusammen und bevorzugen Sie eng gefasste Regeln gegenüber katalogweiten Regeln mit langen Einschränkungslisten.
7.3 Datumsfilter in Berichten setzen Indizes außer Kraft
Wenn eine Spalte in eine Funktion eingebettet wird, ist ihr Index nicht mehr nutzbar. Benutzerdefinierte Dashboards und CSV-Exporte führen dies häufig aus.
-- Langsam: Die Funktion blockiert den Indexzugriff.
SELECT COUNT(*) FROM ps_orders WHERE DATE(date_add) = '2026-03-14';
-- Schnell: Eine halboffene Handelsspanne hält den Index im Spiel.
SELECT COUNT(*) FROM ps_orders
WHERE date_add >= '2026-03-14 00:00:00'
UND date_add < '2026-03-15 00:00:00';
Die Filter `YEAR(date_add)` und die Gruppierung mit `DATE_FORMAT()` weisen denselben Fehler auf. Schreiben Sie sie als Bereiche um, wo immer Sie den Code kontrollieren können. Wenn dies nicht möglich ist – beispielsweise innerhalb eines proprietären Moduls –, unterstützt MySQL ab Version 8.0.13 funktionale Schlüsselbestandteile, sodass Sie den Ausdruck selbst indizieren können. MariaDB bietet keine vergleichbare Funktion, jedoch erzielt eine indizierte, generierte Spalte dort dasselbe Ergebnis.
7.4 Die Bestellbildschirme im Backoffice sind zu komplex.
Die administrative Bestellliste verknüpft die Tabelle „ps_orders“ mit der Tabelle „ps_customer“, den Tabellen für Bestellstatus und Übersetzung sowie den Tabellen für Spediteur, Land und Shop. Anschließend werden die Namen für die Suche verkettet, ein LIKE-Filter angewendet, die Ergebnisse sortiert und paginiert.
Daraus ergeben sich zwei Probleme. Das Filtern oder Sortieren nach einer verknüpften oder übersetzten Spalte (z. B. Kundenname, Statusbezeichnung oder Land) kann keinen Index auf ps_orders verwenden. Daher erstellt MySQL zuerst das verknüpfte Set und sortiert es anschließend. Schlimmer noch: Die Kostenberechnung berücksichtigt die Gesamtzahl der Bestellungen anstatt der Seitengröße, was erklärt, warum die Darstellung mit zunehmender Größe des Shops immer schlechter wird.

Einige Abhilfemaßnahmen kosten nichts: Verringern Sie die Standardseitengröße, halten Sie den Statusfilter schmal und schulen Sie die Mitarbeiter darin, anhand der Bestellreferenz zu suchen, anstatt blind zu blättern.
7.4 Sichere Korrekturen anwenden: Indexierungsstrategie, die Aktualisierungen übersteht
Indizes kommen zuletzt, niemals an erster Stelle. Diese Reihenfolge hat sich bewährt:
- Überarbeiten Sie Ihre bestehenden SQL-Anweisungen. Entfernen Sie Funktionen aus gefilterten Spalten und löschen Sie Joins, die niemand liest.
- Arbeitsaufwand reduzieren. Regeln für inaktive Warenkörbe deaktivieren, Administratorfilter verschärfen.
- Aktualisieren Sie die Statistiken mit ANALYZE TABLE und führen Sie anschließend EXPLAIN ein zweites Mal aus.
- Füge einen einzelnen Index hinzu. Miss ihn vorher und nachher.

Jeder Index verlangsamt Schreibvorgänge und belegt Speicherplatz im Pufferpool, und Warenkorbtabellen absorbieren viel Schreibverkehr. Fügen Sie sie daher bewusst hinzu:
-- Beispiele. Testen Sie zuerst an einer wiederhergestellten Produktionskopie und bestätigen Sie die Ergebnisse mit
-- SHOW INDEX, dass kein gleichwertiger Index existiert.
CREATE INDEX idx_cp_product_cart ON ps_cart_product (id_product, id_cart);
CREATE INDEX idx_cart_dateupd_shop ON ps_cart (date_upd, id_shop);
Ein paar Regeln sorgen dafür, dass die Indizierung der PrestaShop-Bestelltabelle bei Kern- und Modulaktualisierungen erhalten bleibt:
- Nie Ändern Sie den Primärschlüssel oder fügen Sie eine UNIQUE-Einschränkung zu einer Kerntabelle hinzu. Der Kerncode ist von der bestehenden Schlüsselstruktur abhängig, und ein eindeutiger Index kann legitime Einfügungen aus dem Checkout verhindern.
- Nie Ein Kernindex wurde gelöscht, weil er in einer Testabfrage ignoriert wurde. Ein anderer Controller benötigt ihn mit hoher Wahrscheinlichkeit.
- Geben Sie benutzerdefinierten Indexnamen ein eindeutiges Präfix, damit der nächste Entwickler Ihre von den Standardindexnamen unterscheiden kann.
- Speichern Sie jeden benutzerdefinierten Index in einer versionierten Migration mit einem Rollback-Skript und überprüfen Sie ihn nach jedem Upgrade erneut mit SHOW INDEX.
- Erstellen Sie Indizes für sehr große Tabellen während eines Wartungsfensters oder verwenden Sie ein Online-Schemaänderungstool, da ein blockierender ALTER TABLE-Befehl Live-Checkouts unterbrechen kann.
8.0 Alte Warenkorbdaten vor dem Hinzufügen von Hardware löschen und archivieren.
Indizes sind hilfreich, aber die Verkleinerung des Arbeitssets ist oft noch effektiver. Verlassene Wagen enthalten den größten Teil des Leerguts, daher sollten diese zuerst inventarisiert werden:
-- Schreibgeschützt. Wie viel von ps_cart ist unnötiger Ballast?
SELECT COUNT(*) AS abandoned_carts
FROM ps_cart c
LEFT JOIN ps_orders o ON o.id_cart = c.id_cart
WHERE o.id_order IS NULL
UND c.date_upd < DATE_SUB(NOW(), INTERVAL 12 MONTH);
Einige Regeln sind unabdingbar. Löschen Sie niemals einen Warenkorb, der eine Bestellung enthält, da Bestellbildschirme und die Rechnungserstellung diese Daten weiterhin benötigen. Die oben genannte Bedingung LEFT JOIN … IS NULL schützt Sie davor. Löschen Sie untergeordnete Zeilen vor übergeordneten Zeilen, einschließlich ps_cart_product, sowie alle Modultabellen, die auf id_cart basieren. Erstellen Sie zunächst eine Sicherungskopie, üben Sie den Vorgang mit einer wiederhergestellten Kopie und führen Sie die Löschvorgänge in der Produktionsumgebung in kleinen Batches statt als eine große Transaktion während der Handelszeiten durch.
Bewahren Sie die Bestellungen selbst auf. Die Aufbewahrungsvorschriften für Rechnungen und Steuerunterlagen variieren je nach Rechtsgebiet; archivieren Sie diese daher, anstatt sie zu löschen, wenn Sie den Bestand verkleinern müssen.
Tabellen werden wieder aufgefüllt, daher verschafft Ihnen eine einmalige Bereinigung bestenfalls Monate. Füge ein Skript für die Bereinigung hinzu, binde es in die oben beschriebene Reihenfolgeprüfung ein und übergib den Auftrag an deinen Planer. Manuelle Löschvorgänge in der Produktion um 2 Uhr nachts sind fehleranfällig. Führe abschließend `ANALYZE TABLE` aus, damit der Optimierer die neue Zeilenverteilung lernt.
9.0 Behalten Sie die Leistung der PrestaShop-Datenbank im Auge, sonst verschlechtert sie sich wieder.
Regressionen treten unbemerkt auf. Ein Modulupdate enthält eine unachtsame Abfrage, die niemand bemerkt, und die Supportanfragen tauchen erst eine Woche später auf. Routineprüfungen sind in jedem Fall effektiver als die Reaktion auf Vorfälle.

- Planen Sie die Zusammenfassung ein. Führen Sie pt-query-digest wöchentlich über rotierte, langsame Protokolldateien aus und vergleichen Sie die Fingerabdrücke von Woche zu Woche. Neue Einträge decken Regressionen frühzeitig auf.
- Abfrage der Digest-Tabellen. Das Performance-Schema von MySQL aggregiert kontinuierlich jede Anweisung, und das sys-Schema stellt lesbare Ansichten wie statement_analysis und statements_with_full_table_scans bereit.
- Attributabfragen an Code. Ein APM-Tool zeigt Ihnen an, welcher Hook, Controller oder welches Modul eine Abfrage ausgelöst hat. Das Slow-Log nennt die Anweisung; APM nennt den zu korrigierenden Code.
- Die Skala liest die Messwerte separat ab. PrestaShops eigene Skalierungsdokumentation Es wird eine einzelne Schreibinstanz mit Lesereplikaten empfohlen, da das Frontend deutlich mehr Lese- als Schreibvorgänge generiert. Außerdem wird vorgeschlagen, Tabellen nach großen Importen zu analysieren, damit der Optimierer mit aktuellen Statistiken arbeitet.
- Geben Sie dem Pufferpool Raum. Wenn die Datenbank auf einem eigenen Server läuft, erhöhen Sie innodb_buffer_pool_size, bis der Pufferpool so viel Arbeitsspeicher aufnehmen kann, wie Sie verkraften können. Ist der Pufferpool zu klein, stößt ein stark frequentierter PrestaShop-Shop innerhalb weniger Tage an seine Grenzen.
10.0 Fazit
Das Aufspüren langsamer SQL-Abfragen in PrestaShop erfordert methodisches Vorgehen, keine Detektivarbeit. Protokollieren Sie mit einem sinnvollen Schwellenwert, sortieren Sie nach Gesamtzeit und führen Sie EXPLAIN für die obersten Einträge aus. Analysieren Sie anschließend den Ausführungsplan nüchtern. Ein Typ wie ALL, ein NULL-Schlüssel oder die Verwendung von filesort in Extra deuten jeweils auf eine mögliche Rewrite-Regel oder einen Index hin.
Anschließend sollten Sie sich den Daten selbst widmen. Entfernen Sie abgebrochene Warenkörbe, archivieren Sie alte Datensätze, überprüfen Sie Verbesserungen anhand realer Abfragen statt synthetischer Tests und planen Sie die Prüfungen so, dass Regressionen erkannt werden, bevor Kunden sie bemerken. Shops, die diesem Prozess folgen, gewährleisten einen reaktionsschnellen Checkout auch bei steigendem Bestellvolumen und eine effiziente Nutzung ihres Backoffice.
Wenn Sie diese Woche nur eine Sache erledigen, aktivieren Sie das Protokoll für langsame Abfragen in Ihrem am stärksten frequentierten Shop und lesen Sie die ersten zehn Einträge. Diese Liste gibt Ihnen in der Regel Aufschluss darüber, wo im nächsten Monat Datenbankarbeiten anfallen.
Bei Knowband helfen wir PrestaShop-Shop-Betreibern, Leistung, Skalierbarkeit und Stabilität durch zuverlässige PrestaShop-Plugins, die Entwicklung individueller Website-Funktionen und die App-Entwicklung zu verbessern.
Benötigen Sie Hilfe? Kontaktieren Sie uns unter [email protected] oder besuchen Sie den Knowband-Helpdesk.

