it-swarm.com.de

Mehrspaltiger Index und Leistung

Ich habe eine Tabelle mit einem mehrspaltigen Index und ich habe Zweifel an der richtigen Sortierung der Indizes, um die maximale Leistung für die Abfragen zu erzielen.

Das Szenario:

  • PostgreSQL 8.4, Tabelle mit ungefähr einer Million Zeilen

  • Werte in Spalte c1 können ungefähr 100 verschiedene Werte haben. Wir können davon ausgehen, dass die Werte gleichmäßig verteilt sind, sodass wir für jeden möglichen Wert ungefähr 10000 Zeilen haben.

  • Die Spalte c2 kann 1000 verschiedene Werte haben. Wir haben 1000 Zeilen für jeden möglichen Wert.

Bei der Suche nach Daten enthält die Bedingung immer Werte für diese beiden Spalten, sodass die Tabelle einen mehrspaltigen Index hat, der c1 und c2 kombiniert. Ich habe gelesen, wie wichtig es ist, die Spalten zu ordnen in einem mehrspaltigen Index, wenn Sie Abfragen haben, bei denen nur eine Spalte zum Filtern verwendet wird. Dies ist in unserem Szenario nicht der Fall.

Meine Frage ist diese:

Könnte ich angesichts der Tatsache, dass einer der Filter einen viel kleineren Datensatz auswählt, die Leistung verbessern, wenn der erste Index der selektivste ist (derjenige, der einen kleineren Satz zulässt)? Ich hatte diese Frage erst in Betracht gezogen, als ich die Grafiken aus dem Artikel sah, auf den verwiesen wurde:

enter image description here

Bild aus dem Artikel über mehrspaltige Indizes .

Die Abfragen verwenden Werte aus den beiden Spalten zum Filtern. Ich habe keine Abfragen mit nur einer Spalte zum Filtern. Sie sind alle: WHERE [email protected] AND [email protected]. Es gibt auch Bedingungen wie diese: WHERE c1 = "abc" AND c2 LIKE "ab%"

32
jap1968

Antworten

Da Sie auf die Website use-the-index-luke.com Verweisen, beachten Sie das Kapitel:

Verwenden Sie den Index, Luke ›Die Where-Klausel› Suche nach Bereichen › Größer, kleiner und ZWISCHEN

Es gibt ein Beispiel, das perfekt zu Ihrer Situation passt (zweispaltiger Index, einer wird auf Gleichheit getestet, der andere auf Bereich), erklärt (mit mehr von diese schönen Indexgrafiken) warum @ ypercubes Rat ist korrekt und fasst es zusammen:

Rule of thumb: index for equality first — then for ranges.

Auch gut für nur eine Spalte?

Was bei Abfragen zu nur eine Spalte zu tun ist, scheint klar zu sein. Weitere Details und Benchmarks dazu unter dieser verwandten Frage:

Weniger selektive Spalte zuerst?

Was ist, wenn Sie nur Gleichheitsbedingungen für beide Spalten haben?

Es spielt keine Rolle . Stellen Sie die Spalte an die erste Stelle, die mit größerer Wahrscheinlichkeit eigene Bedingungen erhält, was tatsächlich wichtig ist.

Betrachten Sie diese Demo oder reproduzieren Sie sie selbst. Ich erstelle eine einfache Tabelle mit zwei Spalten mit 100.000 Zeilen. Einer mit sehr wenigen, der andere mit Losen mit unterschiedlichen Werten:

CREATE TEMP TABLE t AS
SELECT (random() * 10000)::int AS lots
     , (random() * 4)::int     AS few
FROM generate_series (1, 100000);

DELETE FROM t WHERE random() > 0.9;  -- create some dead tuples, more "real-life"

ANALYZE t;

SELECT count(distinct lots)   -- 9999
     , count(distinct few)    --    5
FROM   t;

Abfrage:

SELECT *
FROM   t
WHERE  lots = 2345
AND    few = 2;

EXPLAIN ANALYZE Ausgabe (Best of 10, um Caching-Effekte auszuschließen):

 Seq Scan auf t (Kosten = 0,00..5840,84 Zeilen = 2 Breite = 8) 
 (Tatsächliche Zeit = 5,646..15,535 Zeilen = 2 Schleifen = 1) 
 Filter: ((Lose = 2345) UND (wenige = 2)) 
 Puffer: lokaler Treffer = 443 
 Gesamtlaufzeit: 15,557 ms 

Index hinzufügen, erneut testen:

CREATE INDEX t_lf_idx ON t(lots, few);
Index-Scan mit t_lf_idx auf t (Kosten = 0,00..3,76 Zeilen = 2 Breite = 8) 
 (Tatsächliche Zeit = 0,008..0,011 Zeilen = 2 Schleifen = 1) 
 Index Cond: (( Lose = 2345) UND (wenige = 2)) 
 Puffer: lokaler Treffer = 4 
 Gesamtlaufzeit: 0,027 ms

Anderen Index hinzufügen, erneut testen:

DROP INDEX t_lf_idx;
CREATE INDEX t_fl_idx  ON t(few, lots);
Index-Scan mit t_fl_idx auf t (Kosten = 0,00..3,74 Zeilen = 2 Breite = 8) 
 (Tatsächliche Zeit = 0,007..0,011 Zeilen = 2 Schleifen = 1) 
 Index Cond: (( wenige = 2) UND (Lose = 2345)) 
 Puffer: lokaler Treffer = 4 
 Gesamtlaufzeit: 0,027 ms
37

Wenn, wie Sie sagen, die Abfragen, die diese 2 Spalten betreffen, alle Gleichheitsprüfungen beider Spalten sind, z.

WHERE [email protected] AND [email protected]

kümmere dich nicht darum. Ich bezweifle, dass es einen Unterschied geben wird, und wenn es einen gibt, wird er vernachlässigbar sein. Sie können natürlich jederzeit mit Ihren Daten und Ihren Servereinstellungen testen. Verschiedene Versionen eines DBMS können sich hinsichtlich der Optimierung geringfügig unterschiedlich verhalten.

Die Reihenfolge innerhalb des Index wäre für andere Arten von Abfragen von Bedeutung, bei denen nur eine Spalte überprüft wird oder Ungleichheitsbedingungen oder Bedingungen in einer Spalte und Gruppierungen in der anderen usw.

Wenn ich eine der beiden Ordnungen wählen würde, würde ich die weniger selektive Spalte an die erste Stelle setzen. Betrachten Sie eine Tabelle mit den Spalten year und month. Es ist wahrscheinlicher, dass Sie eine WHERE year = 2000 - Bedingung oder eine WHERE year BETWEEN 2000 AND 2013 Oder eine WHERE (year, month) BETWEEN (1999, 6) AND (2000, 5) benötigen.

Eine Abfrage vom Typ WHERE month = 7 GROUP BY year Ist möglicherweise sicher (Personen finden, die im Juli geboren wurden), wird aber seltener durchgeführt. Das hängt natürlich von den tatsächlichen Daten ab, die in Ihrer Tabelle gespeichert sind. Wählen Sie zunächst eine Bestellung aus, sagen Sie (c1, c2) Und Sie können später jederzeit einen weiteren Index hinzufügen (c2, c1).


pdate, nach dem Kommentar des OP:

Es gibt auch Bedingungen wie diese: WHERE c1 = 'abc' AND c2 LIKE 'ab%'

Diese Art der Abfrage ist genau eine Bereichsbedingung in der Spalte c2 Und würde einen Index (c1, c2) Benötigen. Wenn Sie auch Fragen vom umgekehrten Typ haben:

WHERE c2 = 'abc' AND c1 LIKE 'ab%'

dann wäre es gut, wenn Sie auch einen (c2, c1) Index hätten.

11
ypercubeᵀᴹ