Zum Inhalt
wannacode

Indizes über mehrere Spalten

Kurz gesagt: Ein zusammengesetzter Index ist ein Index auf mehreren Spalten, der hilft, wenn die Abfrage seine Spalten von links nach rechts verwendet.

Problem

Die letzten zehn

Die Seite „Zuletzt angesehen“ zeigt die letzten 10 Besuche des Kunden, beginnend mit dem neuesten. Der Index auf customer_id ist schon angelegt. Sieh dir den Plan an:

SQLDatenbank: Shop

Der Index findet die 60 Besuche, liefert sie aber nicht nach Datum sortiert. Die Datenbank sortiert sie selbst (USE TEMP B-TREE). Bei einem Kunden mit Tausenden Besuchen ist das der langsamste Teil, und gebraucht werden nur 10 davon.

Die Idee

Zwei Spalten in einem Index

Ein Index kann mehrere Spalten umfassen: CREATE INDEX name ON tabelle(spalte1, spalte2). Das ist ein zusammengesetzter Index. Er ist sortiert wie ein Telefonbuch: zuerst nach Nachnamen, und bei gleichem Nachnamen nach Vornamen.

Der Index auf (customer_id, seen_at) ist zuerst nach Kunden sortiert, und die Besuche eines Kunden sind nach Datum sortiert. Die Datenbank findet den Kunden und liest seine Daten vom Ende rückwärts. Sortieren ist nicht nötig:

SQLDatenbank: Shop

Derselbe Index hilft auch, wenn die Bedingung beide Spalten betrifft. Die Datenbank geht zum Kunden und sucht in dessen Bereich ab dem Datum:

SQLDatenbank: Shop

Und bei der ersten Spalte allein, als wäre es ein Index nur auf customer_id:

SQLDatenbank: Shop

Probier es aus

Besuche in einem Zeitraum

Der Kundendienst fragt oft, wie oft ein Kunde ab einem bestimmten Datum Produkte angesehen hat. Lege einen Index genau auf diese beiden Spalten an, damit die Abfrage sowohl beim Kunden als auch beim Datum ein SEARCH ist.

SQLDatenbank: Shop

Sieh es dir an

Von links nach rechts

Mit demselben Index fragt der Bericht „pro Tag“ nur nach dem Datum:

SQLDatenbank: Shop

Der Plan ist ein SCAN. Er sagt USING COVERING INDEX, weil COUNT(*) aus dem Index berechnet wird, aber die Datenbank liest trotzdem alle 300 000 Einträge darin. Führe die Abfrage selbst aus und sieh dir die Zeit an:

SQLDatenbank: Shop

In einem Telefonbuch findest du nicht alle, die „Maria“ heißen, ohne das ganze Buch zu lesen. Die Vornamen sind nur innerhalb jedes Nachnamens sortiert.

Das ist die Regel von links nach rechts: Ein Index auf (a, b) hilft bei Bedingungen auf a, auf a und b und bei ORDER BY b, wenn a mit = vorgegeben ist. Bei einer Bedingung nur auf b hilft er nicht. Wenn du unsicher bist, prüfe es mit EXPLAIN QUERY PLAN.

Die Idee

Was ein Index kostet

Indizes sind nicht umsonst. Jede neue Zeile muss in jedem Index der Tabelle an ihren Platz geschrieben werden. Die beiden Felder unten fügen je 100 000 Besuche hinzu. Das erste hat keine Indizes, das zweite vier. Führe sie aus und vergleiche die Zeiten:

SQLDatenbank: Shop
SQLDatenbank: Shop

Dasselbe gilt für ein UPDATE einer indizierten Spalte und für DELETE.

Indizes belegen auch Platz. SQLite speichert die Datenbank in Seiten zu 4 096 Byte, und pragma_page_count() sagt, wie viele Seiten es gibt. Hier ist die Datenbank ohne Indizes und mit den vier:

SQLDatenbank: Shop
SQLDatenbank: Shop

Mit den vier Indizes ist die Datenbank mehr als dreimal so groß. Darum legst du Indizes für die Abfragen an, die du wirklich hast, und nicht für jede Spalte „zur Sicherheit“.

Genauer, für Neugierige

Der zweite der vier Indizes, (customer_id, seen_at), macht den ersten, (customer_id), überflüssig: Nach der Regel von links nach rechts erledigt er auch dessen Aufgabe. Solche Paare sind häufig und fallen selten auf. PostgreSQL zählt mit, wie oft jeder Index benutzt wurde (pg_stat_user_indexes), sodass sich die ungenutzten finden lassen.

Übung

Zwei Aufgaben

1. Die Datenbank hat einen Index auf (customer_id) und einen auf (customer_id, seen_at). Entferne den überflüssigen.

Entferne den Index, dessen Aufgabe der andere miterledigt:

SQLDatenbank: Shop

2. Der Index auf (customer_id, seen_at) ist angelegt. Zeige die Daten der letzten 3 Besuche von Kunde 1234, beginnend mit dem neuesten.

Die letzten 3 Besuchsdaten von Kunde 1234:

SQLDatenbank: Shop

Test

Teste dich

1. Es gibt einen Index auf (customer_id, seen_at). Welche Bedingung kann ihn NICHT für eine Suche nutzen?
2. Es gibt einen Index auf (customer_id, seen_at). Brauchst du zusätzlich einen eigenen Index nur auf customer_id?
3. Warum bremsen Indizes INSERT?
4. Wann ist ein Index auf einer Spalte eine gute Idee?

Erstellt von Ivo Gergov im Rahmen der Kampagne von Evo Tech für zugängliche Programmierausbildung ·