Seite wählen

In Datenbanken Indizes benutzen Du sollst!

von | Mrz 10, 2016 | Development, MySQL, PostgreSQL

… hat Bernd schon verlauten lassen.
Das heißt aber nicht, dass pauschal jede Spalte jeder Tabelle indiziert gehört – und es funktioniert. Denn bei jeder Schreiboperation müssen auch alle betroffenen Indizes mit aktualisiert werden. Dies sollte berücksichtigt werden, wenn in eine Tabelle potenziell viel geschrieben wird, aber die Lesevorgänge sich in Grenzen halten. (Beispiel: Icinga 2 DB IDO)
Im folgenden möchte ich genauer auf die Anwendungsfälle von DB-Indizes eingehen. Zwecks Demonstration habe ich eine SQLite-DB mit folgendem Schema angelegt:

CREATE TABLE myheavytable0 (
  c0 INTEGER, c1 INTEGER, c2 INTEGER, c3 INTEGER, c4 INTEGER,
  c5 INTEGER, c6 INTEGER, c7 INTEGER, c8 INTEGER, c9 INTEGER
);
CREATE TABLE myheavytable1 (
  c0 INTEGER, c1 INTEGER, c2 INTEGER, c3 INTEGER, c4 INTEGER,
  c5 INTEGER, c6 INTEGER, c7 INTEGER, c8 INTEGER, c9 INTEGER
);

(2 Tabellen mit je 10 Ganzzahlen-Spalten)
Diese Tabellen habe ich mit je 10.000.000 Zeilen Zufallszahlen befüllt. Im übrigen ist die Indizierung numerischer Spalten potenziell besser als die Indizierung von Text-Spalten.

Anwendungsfall #1: Joins

Die Herstellung von Beziehungen zwischen verschiedenen Entitätsmengen mit Hilfe von Fremdschlüsseln ist bei relationalen Datenbanken das Tagesgeschäft. Es kann sich durchaus lohnen, die entsprechenden Spalten zu indizieren.
Zwecks Demonstration wird das Schema wie folgt ergänzt:

CREATE INDEX myheavyindex0c0 ON myheavytable0 (c0);
CREATE INDEX myheavyindex0c1 ON myheavytable0 (c1);
CREATE INDEX myheavyindex1c0 ON myheavytable1 (c0);
CREATE INDEX myheavyindex1c1 ON myheavytable1 (c1);

(Die ersten 2 Spalten beider Tabellen werden jeweils einzeln indiziert.)
Die Auswirkungen können mit Messungen der Ausführungszeiten folgender Abfragen veranschaulicht werden:

Abfrage Zeit
SELECT COUNT(*) FROM myheavytable0 m0 INNER JOIN myheavytable1 m1 ON m0.c2 = m1.c3 1m 6.519s
SELECT COUNT(*) FROM myheavytable0 m0 INNER JOIN myheavytable1 m1 ON m0.c0 = m1.c3 20.836s
SELECT COUNT(*) FROM myheavytable0 m0 INNER JOIN myheavytable1 m1 ON m0.c0 = m1.c1 4.468s

Daraus folgt: Werden 2 Tabellen mit Hilfe von je einer Spalte, von denen eine indiziert ist, gejoint, ist die Abfrage etwa 3x so schnell wie mit 2 nicht-indizierten Spalten. Sind beide Spalten indiziert, ist die Abfrage fast 15x so schnell.

Anwendungsfall #2: Verrechnung mehrerer Spalten

Manchmal müssen 2 Attribute einer Entität in einer Abfrage miteinander verrechnet werden. Viele Datenbanken bieten lobenswerterweise auch die Möglichkeit, Ausdrücke zu indizieren:

CREATE INDEX myheavyindex0e0 ON myheavytable0 (c4 + c5);
Abfrage Zeit
SELECT COUNT(*) FROM myheavytable0 WHERE c0 + c1 > 8000000 1.324s
SELECT COUNT(*) FROM myheavytable0 WHERE c4 + c5 > 8000000 0.513s

Daraus folgt: Wenn ein indizierter Ausdruck abgefragt wird, ist die Abfrage fast 3x so schnell wie wenn alle am Ausdruck beteiligten Spalten einzeln indiziert sind.

Anwendungsfall #3: Filter auf mehrere Spalten

Wenn abgefragte Daten häufig auf mehreren Spalten basierend gefiltert werden, kann es sich lohnen, diese Spalten zusammen zu Indizieren:

CREATE INDEX myheavyindex0m0 ON myheavytable0 (c6, c7);
Abfrage Zeit
SELECT COUNT(*) FROM myheavytable0 WHERE c0 < 8000000 AND c1 > 8000000 12.130s
SELECT COUNT(*) FROM myheavytable0 WHERE c6 < 8000000 AND c7 > 8000000 0.445s

Daraus folgt: Bei zusammen indizierten Spalten ist die Abfrage 27x so schnell wie bei einzeln indizierten.

Fazit

Bei Nutzung von Indizes hängt viel vom Einzelfall ab. Im Zweifelsfall sollte ein Fachmann zu Rate gezogen werden.

Alexander Klimov
Alexander Klimov
Senior Developer

Alexander hat 2017 seine Ausbildung zum Developer bei NETWAYS erfolgreich abgeschlossen. Als leidenschaftlicher Programmierer und begeisterter Anhänger der Idee freier Software, hat er sich dabei innerhalb kürzester Zeit in die Herzen seiner Kollegen im Development geschlichen. Wäre nicht ausgerechnet Gandhi sein Vorbild, würde er von dort aus daran arbeiten, seinen geheimen Plan, erst die Abteilung und dann die Weltherrschaft an sich zu reißen, zu realisieren - tut er aber nicht. Stattdessen beschreitet er mit der Arbeit an Icinga Web 2 bei uns friedliche Wege.

1 Kommentar

Einen Kommentar abschicken

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Mehr Beiträge zum Thema Development | MySQL | PostgreSQL

Mein PHP-Trainingsprojekt

PHP Schulung Vor kurzem haben wir begonnen, eine neue Programmiersprache zu lernen – PHP. In der ersten Woche haben wir mit den Grundlagen wie Variablen, Arrays, Schleifen begonnen und uns schrittweise zu komplizierterer Syntax wie Funktionen, Objekten und Klassen...

check_prometheus ist jetzt öffentlich verfügbar!

Monitoring ist komplex, das wissen wir hier bei NETWAYS leider zu gut. Deswegen laufen in der Infrastruktur auch mal gerne mehrere Tools für die Überwachung. Zwei gern gesehene Kandidaten sind dabei Icinga und Prometheus. Icinga und Prometheus erfüllen...