MySQL Indexing: Slash Query Times by 96% – BuiltToWinWeb
EN ES FR DE IT PT ZH JA KO RU NL
← Back to all articles

MySQL-Indizierung: Von 2‑Sekunden-Suchen zu 30-ms-Ergebnissen

Ein richtiger Index kann eine 2‑Sekunden-Produktsuche in 30 ms verwandeln – eine Verbesserung von 98 %. Dennoch laufen die meisten WordPress-Seiten nur mit Standard-Indizes, und viele individuelle PHP-Anwendungen werden ohne jede Indizierungsstrategie erstellt. Dieser Leitfaden zeigt Ihnen, wie Sie Indizes entwerfen, die Ihre Datenbank zum Singen bringen.

Warum Indizierung für die Web-Performance wichtig ist

Wenn ein Benutzer eine Seite besucht, die eine Datenbank abfragt (Produktlisten, Suchergebnisse, Benutzerprofile), muss MySQL die relevanten Zeilen finden. Ohne Indizes führt MySQL einen vollständigen Tabellenscan durch – jede Zeile wird gelesen, bis Übereinstimmungen gefunden werden. Für eine Tabelle mit 100.000 Zeilen dauert ein vollständiger Scan 200‑500 ms. Bei 1.000 gleichzeitigen Benutzern werden daraus Sekunden Verzögerung und die Server-CPU ist ausgelastet.

Indizes sind wie das Register eines Buches: Sie sagen MySQL genau, wo die Zeilen zu finden sind, und verwandeln eine O(n)-Operation in eine O(log n)-Operation. Das Ergebnis sind Abfragen, die Ergebnisse in Millisekunden statt Sekunden liefern.

Wie MySQL-Indizes funktionieren (einfach erklärt)

MySQL verwendet standardmäßig B‑Tree-Indizes. Sie speichern Spaltenwerte in einer sortierten Baumstruktur. Wenn Sie eine Abfrage mit einer WHERE-Klausel für eine indizierte Spalte ausführen, durchläuft MySQL den Baum, um die übereinstimmenden Werte in etwa log₂(N) Schritten zu finden. Für 1 Million Zeilen sind das etwa 20 Schritte statt 1 Million Scans.

Wichtige Regel: Indizes helfen beim Filtern nach Gleichheit (=), Bereich (<, >, BETWEEN) oder Präfixübereinstimmung (LIKE 'Begriff%'). Sie können nicht helfen bei LIKE '%Begriff%' (führendes Wildcard) oder Funktionsaufrufen wie WHERE DATE(created_at) = '2025-01-01'.

Identifizierung langsamer Abfragen – Verwendung von EXPLAIN

Bevor Sie Indizes hinzufügen, finden Sie Ihre langsamsten Abfragen. Aktivieren Sie das MySQL Slow Query Log:

SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 0.5;  -- log queries slower than 0.5 seconds
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';

Führen Sie dann mysqldumpslow -s t /var/log/mysql/slow.log aus, um die langsamsten Abfragen zu sehen.

Als Nächstes setzen Sie EXPLAIN vor jede verdächtige Abfrage, um zu sehen, wie MySQL sie ausführt. Zum Beispiel:

EXPLAIN SELECT * FROM products WHERE category_id = 5 AND price < 100;

Schauen Sie auf die Spalte type:

  • ALL – vollständiger Tabellenscan (schlechteste).
  • range oder ref – Verwendung eines Index (gut).
  • const – Primärschlüsselsuche (beste).

Überprüfen Sie auch rows – die Anzahl der gescannten Zeilen. Wenn sie nahe am Tabellengesamtwert liegt, fügen Sie einen Index hinzu.

Praktische Indizierungsstrategie – Einfache vs. zusammengesetzte Indizes

Einzelspalten-Indizes

Verwenden Sie sie, wenn Sie häufig nach einer Spalte filtern.

CREATE INDEX idx_user_id ON orders (user_id);

Zusammengesetzte (Multi‑Spalten-) Indizes

Wenn Sie nach mehreren Spalten filtern, ist ein zusammengesetzter Index weitaus effizienter als separate Indizes. MySQL kann nur einen Index pro Tabellenreferenz verwenden, aber ein zusammengesetzter Index deckt mehrere Spalten ab.

-- Slow: 2 seconds, scans 50,000 rows
SELECT * FROM products WHERE category_id = 5 AND price < 100;

-- Add composite index (order matters!)
CREATE INDEX idx_category_price ON products (category_id, price);

-- Now: 30ms, scans 127 rows

Reihenfolgeregel: Setzen Sie die selektivste Spalte an die erste Stelle (diejenige, die die meisten Zeilen herausfiltert). Normalerweise reduziert category_id 50.000 → 5.000, dann price auf 200. Wenn Sie umkehren (price, category_id), wäre der Index für Bereichsabfragen nach Preis weniger effizient.

Abdeckende Indizes (der Heilige Gral)

Wenn Ihre Abfrage nur Spalten benötigt, die im Index enthalten sind, kann MySQL die Abfrage vollständig aus dem Index beantworten – ohne auf die Tabellendaten zugreifen zu müssen. Das ist extrem schnell.

-- Query only needs id and name
SELECT id, name FROM products WHERE category_id = 5;

-- Covering index
CREATE INDEX idx_category_id_name ON products (category_id, name);

-- EXPLAIN will show "Using index" in Extra column

Praktisches Beispiel: E-Commerce-Produktfilterung – Vorher & Nachher

Ein Online-Shop mit 50.000 Produkten hatte eine Suchseite, die nach Kategorie, Marke und Preisbereich filterte. Die ursprüngliche Abfrage:

SELECT * FROM products 
WHERE category_id = 12 
  AND brand_id IN (3,7,9) 
  AND price BETWEEN 50 AND 200 
ORDER BY price LIMIT 24;

Ohne Index: vollständiger Tabellenscan – 2,3 Sekunden, 50.000 Zeilen gescannt.

Nach Analyse: Sie fügten einen zusammengesetzten Index hinzu:

CREATE INDEX idx_category_brand_price ON products (category_id, brand_id, price);

Ergebnis: Dieselbe Abfrage lief in 80 ms (96 % Verbesserung) und scannte nur 312 Zeilen. Die Seitenladezeit sank von 3,2 Sekunden auf 0,6 Sekunden.

Indizierung für WordPress (falls Sie bleiben müssen)

WordPress ist berüchtigt für langsame Abfragen aufgrund seines generischen Schemas. Die Tabelle wp_postmeta speichert jedes benutzerdefinierte Feld als Schlüssel‑Wert-Paar, was zu Millionen von Zeilen führt. Sie können benutzerdefinierte Indizes hinzufügen, um häufige Abfragen zu verbessern:

-- If you frequently query postmeta by meta_key and meta_value
ALTER TABLE wp_postmeta ADD INDEX idx_meta_key_value (meta_key, meta_value(100));

Aber selbst mit Indizierung leidet WordPress immer noch unter dem Overhead von wp_query. Maßgeschneiderte PHP-Anwendungen, die mit einem geeigneten Schema und Indizes entworfen wurden, sind immer schneller.

Indizes pflegen – Wann hinzufügen, wann entfernen

  • Indizes hinzufügen für Spalten, die in WHERE, JOIN, ORDER BY und GROUP BY verwendet werden.
  • Indizes entfernen für Spalten, die selten verwendet werden oder eine sehr niedrige Kardinalität haben (z. B. eine `status`-Spalte mit nur zwei Werten). Jeder Index verlangsamt INSERT, UPDATE und DELETE, weil MySQL auch den Index aktualisieren muss.
  • Indexnutzung überwachen mit SHOW INDEX FROM table; und SELECT * FROM sys.schema_unused_indexes; (MySQL 8.0).

Werkzeuge für die Indizierungsanalyse

  • EXPLAIN – integriert, beginnen Sie immer hier.
  • MySQL Workbench – visuelles EXPLAIN und Performance-Dashboard.
  • pt‑query‑digest (Percona Toolkit) – analysiert das Slow Query Log und schlägt Indizes vor.
  • phpMyAdmin – Funktion „Profiling“ zur Anzeige von Abfrageausführungsdetails.

Kundenfallstudie: Immobilienplattform

Eine Immobilien-Website hatte 200.000 Objektanzeigen. Benutzer suchten nach Stadt, Preisbereich, Schlafzimmern und Objekttyp. Die Suchseite brauchte 4–6 Sekunden zum Laden, weil die Abfrage jedes Mal die gesamte Tabelle scannte.

Lösung: Nach der Analyse der Slow Logs und der Verwendung von EXPLAIN haben wir einen zusammengesetzten Index hinzugefügt:

CREATE INDEX idx_city_price_beds_type ON properties (city_id, price, bedrooms, property_type);

Wir haben auch die Abfrage geändert, um einen abdeckenden Index zu verwenden, indem wir nur die benötigten Spalten auswählten (id, Titel, Preis, Vorschaubild) anstelle von `SELECT *`.

Ergebnisse:

  • Abfragezeit: 5,2 Sekunden → 90 ms.
  • Server-CPU-Last um 70 % gesunken.
  • Seitenladezeit: 6,5 s → 1,2 s (Frontend inklusive).
  • Benutzerengagement um 34 % gestiegen, da Benutzer langsame Suchen nicht abbrachen.

Häufige Fehler und wie man sie behebt

Fehler 1: Jede Spalte indizieren

Problem: Zu viele Indizes verlangsamen Schreibvorgänge. Behebung: Indizieren Sie nur Spalten, die in WHERE, JOIN oder ORDER BY vorkommen.

Fehler 2: Verwendung von Funktionen auf indizierten Spalten

Schlecht: WHERE DATE(created_at) = '2025-01-01' – ignoriert den Index auf created_at. Gut: WHERE created_at BETWEEN '2025-01-01 00:00:00' AND '2025-01-01 23:59:59'.

Fehler 3: Führendes Wildcard in LIKE

Schlecht: WHERE name LIKE '%widget%' – verwendet niemals einen Index. Gut: Verwenden Sie einen Volltextsuchindex für partielle Übereinstimmungen.

Fehler 4: EXPLAIN vorher und nachher nicht verwenden

Führen Sie immer EXPLAIN aus, bevor Sie einen Index hinzufügen, und erneut danach, um die Verbesserung zu überprüfen.

Fortgeschritten: Automatisieren von Indexvorschlägen

Für MySQL 8.0 können Sie das Performance Schema aktivieren und das sys-Schema verwenden, um fehlende Indizes zu finden:

SELECT * FROM sys.schema_unused_indexes;
SELECT * FROM sys.schema_redundant_indexes;

Für ältere Versionen analysiert pt-index-usage von Percona-Toolkit die Slow Logs und schlägt Indizes vor.

Bereit, Ihre Datenbank zu optimieren?

Ich entwickle maßgeschneiderte PHP-Anwendungen von Anfang an mit einer angemessenen Datenbankindizierung. Ob Sie eine langsame WordPress-Seite oder eine benutzerdefinierte Anwendung mit Abfrageengpässen haben, ich kann Ihre Slow Logs analysieren, die richtigen Indizes hinzufügen und die Seitenladezeiten oft um 50 % oder mehr reduzieren.

Sprechen wir über Ihre Datenbankleistungsprobleme. Ich biete eine kostenlose Bewertung Ihrer langsamsten Abfragen an.

Optimieren Sie Ihre Datenbank mit mir →

Alle Leistungszahlen stammen aus realen Kundenprüfungen mit MySQL 8.0 auf Hostinger VPS. Ihre Ergebnisse können je nach Tabellengröße und Serverhardware variieren.