aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Game-Server

MySQL-Index-Optimierung: Langsame Queries lösen

Richtig eingesetzt verwandelt ein MySQL-Index eine Abfrage, die Sekunden dauert, in eine, die Millisekunden braucht; nachlässig eingesetzt bringt er gar nichts und kann sogar deine Schreibvorgänge verlangsamen. Gerade auf Gameservern wachsen Tabellen für Sessions, Logs, Inventar und Ranglisten schnell auf Millionen von Zeilen an. An diesem Punkt musst du den Engpass messen, statt ihn zu raten. In diesem Leitfaden gehen wir Schritt für Schritt durch, wie du langsame Abfragen mit EXPLAIN diagnostizierst, welche Spalten du indexieren solltest und wie du die häufigsten Fehler vermeidest.

Warum Indizes funktionieren

In einer Tabelle ohne Index durchsucht MySQL die gesamte Tabelle von Anfang bis Ende, um die gesuchten Zeilen zu finden (ein Full Table Scan). Je größer die Tabelle wird, desto linearer wird das langsamer. Ein Index ist in den meisten Fällen eine B-Tree-Struktur: Er hält die Werte der indexierten Spalte sortiert und lässt MySQL mit einer Logik ähnlich der binären Suche direkt zum relevanten Block springen, selbst über Millionen von Zeilen.

Das hat seinen Preis: Jedes INSERT, UPDATE und DELETE muss auch den Index aktualisieren. Ein Index beschleunigt also das Lesen, verlangsamt das Schreiben ein wenig und verbraucht Speicherplatz. Deshalb lautet das Ziel nicht „alles indexieren", sondern die richtigen Spalten zu indexieren.

Die langsame Abfrage finden: das Slow Query Log

Zuerst musst du herausfinden, welche Abfrage wirklich langsam ist. Das Slow Query Log von MySQL protokolliert jede Abfrage, die länger als ein von dir festgelegter Schwellenwert läuft. Du kannst es pro Sitzung schnell aktivieren:

SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;        -- Abfragen länger als 1 Sekunde
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';

Nachdem es eine Weile gelaufen ist, fasst du die häufigsten und langsamsten Abfragen mit mysqldumpslow zusammen:

mysqldumpslow -s t /var/log/mysql/slow.log | head -20

Ziel ist es, eine konkrete Abfrage zum Optimieren zu finden. Arbeite mit echtem Traffic, nicht mit Vermutungen.

Diagnose mit EXPLAIN

Sobald du eine langsame Abfrage hast, siehst du mit EXPLAIN, wie MySQL sie ausführt. Eine Beispielabfrage von einem Gameserver:

EXPLAIN SELECT * FROM player_logs
WHERE account_id = 4815 AND action = 'login'
ORDER BY created_at DESC
LIMIT 20;

Achte in der Ausgabe vor allem auf diese Spalten:

  • type: die Zugriffsmethode. ALL ist schlecht (vollständiger Scan), ref und range sind gut, const/eq_ref sind am besten.
  • key: der Index, den MySQL tatsächlich verwendet hat. NULL bedeutet, dass gar kein Index genutzt wurde.
  • rows: die geschätzte Anzahl Zeilen, die MySQL zu scannen erwartet. Weniger ist besser.
  • Extra: Siehst du Using filesort oder Using temporary, wird zusätzliche Arbeit für Sortierung oder Gruppierung geleistet.

Für einen detaillierteren Plan führt EXPLAIN ANALYZE (MySQL 8.0.18+) die Abfrage tatsächlich aus und zeigt die gemessenen Zeiten — du siehst die realen Kosten statt einer Schätzung.

Den richtigen Index entwerfen

Die obige Abfrage filtert nach account_id und action und sortiert nach created_at. Der ideale Index ist ein zusammengesetzter (Composite-)Index, der genau diese Reihenfolge widerspiegelt:

CREATE INDEX idx_logs_acc_action_time
  ON player_logs (account_id, action, created_at);

Das zentrale Konzept hier ist die Leftmost-Prefix-Regel. Ist ein zusammengesetzter Index (a, b, c), kann MySQL ihn für Suchen auf a, a+b oder a+b+c nutzen, aber nicht für b oder c allein. Deshalb ist die Spaltenreihenfolge wichtig:

  • Gleichheitsfilter (=) kommen zuerst (hier account_id, action).
  • Danach folgt die Range- und ORDER BY-Spalte (created_at).

Dank dieser Reihenfolge erledigt MySQL sowohl das Filtern als auch das Sortieren über den Index, und Using filesort verschwindet.

Häufige Fehler

  • Eine Spalte in eine Funktion packen: WHERE DATE(created_at) = '2026-06-27' zu schreiben verhindert die Nutzung des Index. Verwende stattdessen einen Bereich: WHERE created_at >= '2026-06-27' AND created_at < '2026-06-28'.
  • Führender Platzhalter: LIKE '%abc' deaktiviert den Index, während LIKE 'abc%' ihn nutzen kann.
  • Typ-Mismatch: eine numerische Spalte mit einem String wie WHERE id = '123' zu vergleichen, kann eine implizite Konvertierung und einen vollständigen Scan auslösen.
  • Über-Indexierung: selten abgefragte oder wenig selektive Spalten (z. B. ein Flag mit nur 0/1-Werten) allein zu indexieren bringt meist nichts.
  • Unnötiges SELECT *: Wählst du nur die benötigten Spalten, deckt manchmal der Index selbst die ganze Abfrage ab (ein Covering Index) und die Tabelle wird nie angefasst.

Überprüfen und pflegen

Führe nach dem Hinzufügen eines Index dasselbe EXPLAIN erneut aus: type sollte von ALL auf ref/range wechseln, rows sollte stark sinken und filesort sollte verschwinden. Um die Statistiken aktuell zu halten, führe gelegentlich ANALYZE TABLE player_logs; aus. Unbenutzte Indizes kannst du über die View sys.schema_unused_indexes aufspüren und entfernen, um die Schreiblast zu senken.

Denk daran: Index-Optimierung ist keine einmalige Aufgabe, sondern ein kontinuierlicher Kreislauf — messen, indexieren, überprüfen, wiederholen.

Häufige Fragen

Wie viele Indizes kann ich einer Tabelle hinzufügen?

Auch wenn das technische Limit hoch ist, hängt das praktische Limit von deiner Arbeitslast ab. Halte bei schreibintensiven Tabellen die Indizes wenige und präzise; bei leseintensiven Reporting-Tabellen können mehr Indizes sinnvoll sein. Denk daran, dass jeder Index Schreib- und Speicherkosten verursacht.

Sind getrennte Indizes oder ein zusammengesetzter Index besser?

Filtert eine Abfrage mehrere Spalten gemeinsam, ist ein korrekt geordneter zusammengesetzter Index fast immer besser als getrennte Ein-Spalten-Indizes. In den meisten Fällen nutzt MySQL pro Abfrage einen einzigen Index am effizientesten.

Ist der Primärschlüssel bereits ein Index?

Ja. In InnoDB ist der Primärschlüssel zugleich der Clustered Index, und die Zeilendaten werden physisch in seiner Reihenfolge gespeichert. Deshalb ist die Wahl eines kurzen, sequenziellen und unveränderlichen Primärschlüssels (etwa eines Auto-Increments) wichtig für die Performance.

Hör auf zu raten, wenn deine Datenbank langsamer wird. Gameserver oder Webanwendung, egal — lass uns deine langsamen Abfragen gemeinsam messen und die richtige Index-Strategie aufbauen. Kontaktiere mich und wir beschleunigen deine Datenbank.

Bu kategorideki tüm yazılar →

Devamı için