Warum Ihr Online-Shop langsam ist: Die versteckte MySQL-Bremse
In 80% der Fälle ist die Datenbank falsch indexiert. Jede Sekunde Ladezeit kostet 7% Conversion. Die Lösung: 2 Stunden Arbeit statt neuer Hardware.
Warum Ihr Online-Shop langsam ist: Die versteckte MySQL-Bremse
Performance-Optimierung für E-Commerce: Was Shop-Betreiber über Datenbank-Indexierung wissen müssen
Das Problem kennen Sie
Ihr Shop läuft. Die Produkte sind da. Der Traffic kommt. Aber:
- Produktsuche dauert 3-4 Sekunden statt unter 1 Sekunde
- Kategorie-Seiten laden quälend langsam
- Checkout bricht ab weil Kunden nicht warten
- Unter Last bricht alles zusammen
Die Hosting-Firma sagt: "Mehr RAM kaufen!" Die Agentur sagt: "Neuer Server nötig!" Beide kosten 5-stellig.
Die Realität: In 80% der Fälle ist die Datenbank falsch indexiert. Lösung: 2 Stunden Arbeit statt neuer Hardware.
Was Sekunden kosten: Die harte Wahrheit
Jede Sekunde Ladezeit kostet Sie 7% Conversion.
Rechnen Sie selbst:
- Ihr Shop macht CHF 50.000/Monat
- Ladezeit aktuell: 3 Sekunden
- Optimiert auf: 1 Sekunde
- 2 Sekunden schneller = 14% mehr Umsatz = CHF 7.000/Monat mehr
Das sind CHF 84.000 pro Jahr, die Sie aktuell liegen lassen.
Der häufigste Fehler: UUID als Produkt-ID
Das Setup (falsch, aber verbreitet)
Viele Shop-Systeme verwenden UUIDs für Produkt-IDs:
CREATE TABLE products (
product_id VARCHAR(36) PRIMARY KEY, -- z.B. "a3f2e1b0-..."
sku VARCHAR(50),
name VARCHAR(255),
price DECIMAL(10,2),
stock INT
) ENGINE=InnoDB;
Warum machen das Entwickler?
- "Sieht professionell aus"
- "Keine ID-Collision bei Migrationen"
- "Sicher, weil nicht erraten bar"
Was es wirklich macht: Ihren Shop langsam.
Die Benchmark-Wahrheit
Das Standardwerk "High Performance MySQL" hat gemessen:
| Produkte | Sequential ID | UUID | Unterschied |
|---|---|---|---|
| 1 Million | 137s | 180s | 1.3x langsamer |
| 3 Millionen | 1.233s | 4.525s | 3.7x langsamer |
Bei 3 Millionen Produkten ist UUID 3.7x langsamer!
Index-Größe ist dabei 60-65% größer. Bei großen Shops bedeutet das:
- Mehr RAM nötig (teuer)
- Langsamere Backups
- Längere Deployments
Warum UUID so problematisch ist
MySQL InnoDB speichert Daten sortiert nach Primary Key.
Bei normalen IDs (1, 2, 3, 4, ...):
- Neue Produkte werden hinten angefügt
- Schnell, sequentiell, effizient
Bei UUID (random):
- Neue Produkte landen irgendwo mittendrin
- MySQL muss Pages aufbrechen (Page Splits)
- Random Writes statt Sequential
- Fragmentierung über Zeit
Resultat: Insert von 1000 Produkten dauert nicht 10 Sekunden, sondern 40 Sekunden.
Die Lösung: Hybrid-Ansatz
CREATE TABLE products (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, -- Schnell!
uuid BINARY(16) UNIQUE NOT NULL, -- Für API
sku VARCHAR(50),
name VARCHAR(255),
price DECIMAL(10,2),
INDEX idx_uuid (uuid) -- Für externe Lookups
) ENGINE=InnoDB;
Best of both worlds:
- Interne JOINs nutzen
id(schnell) - REST API verwendet
uuid(sicher) - Imports sind 3-4x schneller
Der zweite Killer: Falsche Index-Reihenfolge
Typisches Shop-Szenario
Ihre Kunden filtern nach:
- Kategorie
- Preis-Range
- Auf Lager
-- Ihre häufigste Query
SELECT * FROM products
WHERE category_id = 5
AND price BETWEEN 50 AND 200
AND stock > 0;
Der falsche Index
-- Was viele machen (FALSCH!)
CREATE INDEX idx_filter ON products(stock, price, category_id);
Problem: MySQL kann nur den leftmost prefix nutzen.
Ihre Query sucht zuerst nach category_id, aber der Index beginnt mit stock.
→ Index wird NICHT verwendet
→ Full Table Scan über 500.000 Produkte
Der richtige Index
Regel: Höchste Selektivität zuerst, Ranges am Ende.
-- Analyse: Welche Spalte ist am selektivsten?
SELECT
COUNT(DISTINCT category_id) / COUNT(*) as cat_sel,
COUNT(DISTINCT stock > 0) / COUNT(*) as stock_sel
FROM products;
-- Ergebnis:
-- cat_sel: 0.15 (15% unique → gut!)
-- stock_sel: 0.002 (nur 2 Werte: ja/nein → schlecht)
-- RICHTIGER Index:
CREATE INDEX idx_filter_optimized
ON products(category_id, stock, price);
Performance-Impact:
- Vorher: 500.000 Rows examined
- Nachher: 120 Rows examined
- 4000x schneller!
Real-World Beispiel: Produktsuche
Ein Kunde kam mit diesem Problem:
-- Suche auf Shop (15.000 Anfragen/Tag)
SELECT product_id, name, price, image_url
FROM products
WHERE category_id = ?
AND status = 'active';
Vorher: 2.8s durchschnittlich Nachher (optimierter Index): 0.04s 70x schneller!
ROI-Rechnung:
- 15.000 Suchen/Tag × 2.76s gespart = 11.5 CPU-Stunden/Tag eingespart
- Server-Last: -60%
- Conversion: +12% (wegen Geschwindigkeit)
Covering Indexes: Der Performance-Turbo
Das Konzept
Ein Covering Index enthält alle Spalten, die die Query braucht.
Normale Query-Ausführung:
- Index durchsuchen → Produkt-IDs finden
- Für jede ID: Haupttabelle aufrufen (Random Read!)
- Daten zusammensetzen
Mit Covering Index:
- Index durchsuchen → Alle Daten direkt im Index
- Fertig!
Shop-Beispiel: Listing-Seite
-- Typische Kategorie-Seite Query
SELECT product_id, name, price, image_url
FROM products
WHERE category_id = 5
AND status = 'active'
ORDER BY price ASC
LIMIT 20;
-- OHNE Covering Index:
CREATE INDEX idx_cat ON products(category_id, status);
-- Problem: Muss für jedes Produkt image_url aus Haupttabelle holen
-- Bei 500 Produkten in Kategorie: 500 Random Reads
-- MIT Covering Index:
CREATE INDEX idx_cat_covering
ON products(category_id, status, price, product_id, name, image_url);
-- Alle Daten im Index: 0 Random Reads!
Messbarer Impact:
- Query-Zeit: 450ms → 18ms (25x schneller)
- Server-Load: -70%
- Customer Experience: Instant statt lag
Trade-off verstehen
Vorteil:
- Dramatisch schnellere Reads
Nachteil:
- Index ist größer
- Writes (INSERT/UPDATE) minimal langsamer
Faustregel: Für read-heavy Queries (>90% der Shop-Queries) lohnt sich Covering Index fast immer.
Das unterschätzte Problem: Veraltete Statistics
Was sind Statistics?
MySQL merkt sich:
- Wie viele Rows in Tabelle?
- Wie viele unique Values pro Spalte?
- Wie sind Daten verteilt?
Der Query Optimizer nutzt diese Daten um zu entscheiden:
- Welchen Index verwenden?
- In welcher Reihenfolge JOINs machen?
Problem: Statistics werden nicht automatisch aktualisiert.
Real-World Desaster
Ein Shop startete 2020 mit diesen Daten:
- Orders: 10.000
- Status "completed": 95%
MySQL lernte: "completed ist nicht selektiv"
2024, nach 4 Jahren:
- Orders: 2 Millionen
- Status "completed": 20% (viele neue Stati)
ABER: MySQL nutzt alte Statistics!
Query WHERE status = 'pending' macht Full Table Scan statt Index, weil Optimizer denkt "pending ist selten".
Lösung:
-- Statistics neu berechnen
ANALYZE TABLE orders;
-- Automatisierung (wöchentlich, nachts)
CREATE EVENT weekly_stats
ON SCHEDULE EVERY 1 WEEK
STARTS '2024-01-08 03:00:00'
DO
ANALYZE TABLE products, orders, customers;
Impact bei diesem Kunden:
- Checkout-Queries: 3.2s → 0.3s
- Cart-Updates: 1.8s → 0.2s
Performance-Audit in 30 Minuten
Schritt 1: Slow Query Log aktivieren
# my.cnf
[mysqld]
slow_query_log = 1
long_query_time = 1.0
log_queries_not_using_indexes = 1
Schritt 2: Top-Probleme finden
# Mit Percona Toolkit
pt-query-digest /var/log/mysql/slow-query.log --limit 10
Output zeigt:
- Welche Queries sind am langsamsten?
- Wie oft werden sie aufgerufen?
- Wie viele Rows werden untersucht vs. zurückgegeben?
Schritt 3: EXPLAIN analysieren
EXPLAIN
SELECT * FROM products
WHERE category_id = 5 AND stock > 0;
Red Flags:
type: ALL→ Full Table Scan (SCHLECHT!)rows: 500000→ Untersucht alle ProdukteExtra: Using filesort→ Muss sortieren (langsam)
Schritt 4: Index erstellen & testen
CREATE INDEX idx_test ON products(category_id, stock);
-- Vorher/Nachher vergleichen
EXPLAIN SELECT ...;
Ziel:
type: refoderrange(GUT!)rows: 100statt 500.000- Kein "Using filesort"
Was das für Ihren Shop bedeutet
Typische Verbesserungen die wir sehen:
Produkt-Listings:
- Vorher: 2-4 Sekunden
- Nachher: 0.1-0.3 Sekunden
- 10-20x schneller
Suchfunktion:
- Vorher: 3-5 Sekunden
- Nachher: 0.2-0.5 Sekunden
- 15x schneller
Checkout-Prozess:
- Vorher: 1.5-3 Sekunden
- Nachher: 0.1-0.2 Sekunden
- 20x schneller
Business Impact
Ein mittelgroßer Shop (CHF 80k/Monat) nach Optimierung:
Technische Metriken:
- Durchschnittliche Response: 2.8s → 0.4s
- Server CPU: 85% → 35%
- Absprungrate: 45% → 28%
Business Metriken:
- Conversion Rate: +18%
- Umsatz: CHF 80k → CHF 94k/Monat
- +CHF 168.000/Jahr
Investition: 8 Stunden Analyse + Optimierung
Die 5 wichtigsten Takeaways
-
UUID als Primary Key kostet Performance → Hybrid-Ansatz: Sequential ID + UUID Spalte
-
Index-Reihenfolge ist kritisch → Höchste Selektivität zuerst, Ranges am Ende
-
Covering Indexes für häufige Queries → 10-50x schneller bei Read-Heavy Workloads
-
Statistics regelmäßig aktualisieren →
ANALYZE TABLEwöchentlich -
Messen, dann optimieren → Slow Query Log + EXPLAIN = Ihre besten Freunde
Interesse an Shop Performance-Optimierung?
Kostenloses Erstgespräch & Bedarfsabklärung
Über MEMOTECH
26 Jahre E-Commerce-Expertise. Von Fortune 500 (Deutsche Telekom, Sony Music) zu Swiss KMUs.
Spezialisiert auf:
- Shop-Performance-Optimierung
- MySQL/MariaDB Tuning
- Shopware & Magento
- Multi-Channel Operations (Marello Partner)
Swiss Quality. German Engineering. Direkt vom Inhaber.
Mehmet Gökçe Software & Data Engineer contact@memotech.ch
Technische Referenzen
Benchmark-Daten: Baron Schwartz et al., High Performance MySQL, 4th Edition, O'Reilly 2021, Kapitel 7
Performance-Studien:
- Amazon: 100ms slower = 1% less sales
- Google: 500ms slower = 20% less traffic
- Shop-Performance Correlation Studies 2024
Kontakt
MEMOTECH Software & Data Engineering Schweiz
📧 contact@memotech.ch 🌐 memotech.ch ⏱️ Response < 4 Stunden
Kostenlose Bedarfsanalyse buchen: https://memotech.ch/#contact

Mehmet Gökçe
Founder & CEO
Gründer von MEMOTECH mit über 26 Jahren Erfahrung. Spezialisiert auf E-Commerce-Lösungen und digitale Transformation für Schweizer KMU.