Reihenfolge der Spalten in einem zusammengesetzten Index in PostgreSQL (und Abfragereihenfolge)

9

Ich habe eine Tabelle mit 50.000 Zeilen. Es ist eigentlich eine PostGIS-Tabelle.

Die Abfrage besteht aus 4 Teilen (1 obligatorisch) (3 optional)

  1. Kreuzungsfeld (ein geografisches Rechteck) mit 4 Lat, lang (ich verwende st_intersects) [Obligatorisch]
  2. Datumsbereich (min, max) in einem Datumsfeld
  3. Der Dateityp (ein Satz von bis zu 8 Textwerten) verwendet derzeit IN (.....), aber ich kann dies bei Bedarf zu einer temporären Tabelle machen. Ich sehe, dass viele Leute IN nicht mögen.
  4. Land (ein Textwert).

Ich erwarte ungefähr 100 - 4.000 zurückgegebene Zeilen

Wenn ich einen zusammengesetzten Index für die Tabelle erstelle, welche Spalte sollte ich zuerst verwenden. Die Feinkörnigkeit ist wahrscheinlich der Standort (Daten sind über die ganze Welt verteilt). Ich habe es derzeit als GIST-Index.

Die anderen Indizes wären BTREE.

Meine Intuition sagt, verwenden Sie feinkörnig und natürlich zuletzt. ZB gibt es nur ungefähr 12 Dateitypen, das wären also sehr große Buckets für den Index.

Was sagen die PostgreSQL- und PostGIS-Gurus (die die Interna des Systems kennen)?


AKTUALISIEREN:

Lassen Sie mich diese Frage schärfen.

  1. Ich möchte nicht, dass jemand die Arbeit machen muss, die ich machen sollte. Ich respektiere deine Zeit zu sehr. Also werde ich später zur Erklärungsanalyse kommen.
  2. Ich suchte nur nach Hinweisen, Tipps und Richtlinien.
  3. Ich habe diesen ausgezeichneten kleinen Beitrag gelesen: https://devcenter.heroku.com/articles/postgresql-indexes#managing-and-maintaining-indexes über Indizes
  4. Normalerweise erstelle ich 4 separate Indizes (Geobox, Ländername, Dateityp und Datum), möchte aber sehen, was eine zusammengesetzte Abfrage bewirken würde.

Sagen Sie mir, ob eine dieser Annahmen falsch ist. (Ich bin ziemlich neu in der Idee von zusammengesetzten Indizes)

  1. Ordnung ist wichtig. Wählen Sie als ersten Index den Index, der die Zeilen am meisten abschneidet (in meinem Fall ist die Position (Geografie), bei der es sich um ein einfaches Polygon oder ein Multipolygon handelt, am besten geeignet).
  2. Manchmal überspringen Abfragen Indizes. Wenn ich jedoch eine zusammengesetzte Abfrage mit dem Schlüssel (Nr. 1, Nr. 2, Nr. 3, Nr. 4) erstelle, verwendet der Planer auch dann die einzelne zusammengesetzte Abfrage, wenn er nach Nr. 1, Nr. 3 fragt ist gewartet.
  3. Normalerweise würde ich drei BTREE-Abfragen und eine GIST (für den Geografietyp) erstellen. PostGIS unterstützt nicht das Erstellen einer Verbindung aus mehreren Indextypen. Also muss ich den zusammengesetzten Index GIST verwenden. Aber das sollte nicht schaden.
  4. Wenn ich zusätzliche zusammengesetzte oder Einzelwertindizes erstelle, ist der Planer klug genug, um den intelligentesten auszuwählen .....
  5. Der Ländername kann ungefähr 250 verschiedene Werte haben und ist offensichtlich stark mit dem Standort (Geobox) verbunden. Wenn der nächstbeste Index zum Reduzieren der Zeilengröße jedoch Dateityp ist, sollte ich diesen als nächstes verwenden. Ich erwarte nicht, dass die Benutzer häufig Land oder Datum in ihren Abfragesätzen verwenden.
  6. Ich muss mich NICHT darum kümmern, einen zusammengesetzten Index mit 4 Schlüsseln zu erstellen, um die Größe der Indexdaten erheblich zu erhöhen. Das heißt, wenn ein Ein-Schlüssel-Index 90% der Leistungssteigerung ausmachen würde, schadet es nicht, 3 weitere Elemente hinzuzufügen, um ihn zusammenzusetzen. Umgekehrt sollte ich wirklich beide Indizes erstellen. Ein einzelner geografischer Index sowie ein zusammengesetzter Index. Lassen Sie den Planer herausfinden, welcher am besten ist, und berücksichtigen Sie dabei die Größe der Indextabelle.

Auch hier bitte ich niemanden, meine Lösung zu entwerfen, ich mache mir keine Gedanken über die Arbeit anderer. Aber ich brauche Dinge, die mir die PostGreSQL-Dokumentation nicht über die Implementierung sagt

[Der Grund, warum ich noch kein EXPLAIN-Ergebnis anzeigen kann, ist, dass ich diese 25K-Zeilentabelle aus einer 24M-Zeilentabelle erstellen muss. Es dauert länger als ich dachte. Ich gruppiere Dinge in 1.000 Elementgruppen und lasse den Benutzer die 25K-Zeilentabelle abfragen. Aber meine nächste Frage wird beinhalten, die Ergebnisse dieser Abfrage zu verwenden, um zur MASTER 25M-Zeilentabelle zu gehen und Dinge herauszuholen, und hier wird die Leistung des zusammengesetzten Index wirklich HIT].


Beispielabfrage unten:


SELECT
    public.product_list_meta_mv.cntry_name       AS country,
    public.product_list_meta_mv.product_producer AS producer,
    public.product_list_meta_mv.product_name     AS prod_name,
    public.product_list_meta_mv.product_type     AS ptype,
    public.product_list_meta_mv.product_size     AS size,
    ST_AsGeoJSON(public.product_list_meta_mv.the_geom, 10, 2)          AS outline
FROM
    public.product_list_meta_mv 
WHERE
    public.product_list_meta_mv.cntry_name = 'Poland' 
AND
    ST_Intersects(public.product_list_meta_mv.the_geom,
    st_geogfromtext('SRID=4326;POLYGON((21.23107910156250 51.41601562500000,
                                        18.64379882812500 51.41601562500000,
                                        18.64379882812500 48.69415283203130,
                                        21.23107910156250 48.69415283203130,
                                        21.23107910156250 51.41601562500000))')) 
AND (date >= '1/2/1900 5:00:00 AM' 
 AND date <= '2/26/2014 10:26:44 PM')
AND (public.product_list_meta_mv.product_type in
    ('CIB10','DTED0','DTED1','DTED2','CIB01','CIB05')) ;

EXPLAIN ANALYZE-Ergebnisse (Ich habe keine zusammengesetzten Indizes eingegeben, und von der Geschwindigkeit, die ich sehe, weiß ich nicht, ob ich muss).

"Bitmap Heap Scan on catalog_full cat  (cost=4.33..37.49 rows=1 width=7428) (actual time=1.147..38.051 rows=35 loops=1)"
"  Recheck Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"  Filter: (((type)::text = ANY ('{CADRG,CIB10,DTED1,DTED2}'::text[])) AND (_st_distance('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography, outline, 0::double precision, false) < 1e-005::double precision))"
"  Rows Removed by Filter: 61"
"  ->  Bitmap Index Scan on catalog_full_outline_idx  (cost=0.00..4.33 rows=8 width=0) (actual time=0.401..0.401 rows=96 loops=1)"
"        Index Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"Total runtime: 38.109 ms"

EXPLAIN ANALYZE SELECT pid,product_name,type,country,date,size,cocom,description,egpl_date,ST_AsGeoJSON(outline, 10, 2) AS outline 
FROM portal.catalog_full AS cat 
WHERE ST_Intersects(st_geogfromtext('SRID=4326;POLYGON((21.2200927734375 51.38031005859375, 18.65478515625 51.38031005859375, 18.65478515625 48.7298583984375, 21.2200927734375 48.7298583984375, 21.2200927734375 51.38031005859375))'), cat.outline) 
AND (cat.type in ('CADRG','CIB10','DTED1','DTED2'))
Dr.YSG
quelle
2
Geben Sie bitte die eigentliche Abfrage an.
Ypercubeᵀᴹ
Bedeutet die "3 optional", dass die Abfrage 8 verschiedene Variationen haben kann (abhängig davon, ob die 2,3,4-Optionen aktiviert sind oder nicht)?
Ypercubeᵀᴹ
Es gibt 4 UND-Komponenten für das WO. Auf den st_intersects ist erforderlich, die anderen sind möglicherweise vorhanden oder nicht. Aber ich möchte mich mit dem Fall befassen, in dem sie alle anwesend sind.
2
Ich habe dafür gestimmt, die Frage nach dba.se zu migrieren. Dies ist eine komplexe Abfrage mit mehreren Bereichsbedingungen.
Ypercubeᵀᴹ
1
Zeigen Sie EXPLAIN ANALYZEfür die Abfrage.
Craig Ringer

Antworten:

4

Als Teil meiner Arbeit pflege ich eine ziemlich große PostgreSQL-Datenbank (ca. 120 GB auf der Festplatte, mehrere Tabellen mit mehreren Millionen Zeilen) und habe einige Tricks gesammelt, wie die Abfragen beschleunigt werden können. Zunächst einige Kommentare zu Ihren Annahmen:

  1. Ja, die Reihenfolge ist wichtig, aber nur die erste ist wirklich anders, der Rest sind Indizes zweiter Klasse.
  2. Ich bin mir nicht sicher, ob immer beides verwendet wird. Ich vermute, dass der Abfrageplaner die Nummer 1 verwendet und dann mit dem Rest etwas Kluges macht.
  3. Ich habe keine Erfahrung mit GIST.
  4. Ja, fügen Sie zuerst alle Indizes hinzu, und sehen Sie, was am häufigsten verwendet wird und was die beste Leistung bietet.
  5. Ich würde vorschlagen, dass Sie beide versuchen und messen, was am besten funktioniert. Versuchen Sie, die SQL mit verschiedenen Unterabfragen neu zu schreiben, z. B. Land und Zeit in einer, und verbinden Sie sich dann mit der Intersect-Abfrage. Ich habe keine Leistungsprobleme mit IN-Klauseln festgestellt, solange die IN-Liste nicht Tausende von Elementen umfasst. Ich vermute, dass einige verschiedene Abfragen, die abhängig von den verfügbaren Eingabekriterien speziell abgestimmt wurden, die besten Ergebnisse liefern.
  6. Ich würde vorschlagen, keinen 4-Wege-Index zu erstellen. Versuchen Sie, eine zu erstellen, und überprüfen Sie dann die Größe. Sie können sehr groß werden. Nach meiner Erfahrung waren vier 1-Schlüssel-Indizes fast so schnell wie ein einzelner 4-Wege-Index. Ein Trick, der für bestimmte Abfragen gut funktioniert, sind Teilindizes, dh etwa so:

    CREATE INDEX ON table_x (Schlüssel1, Schlüssel2, Schlüssel3) WHERE some_x_column = 'XXXX';

Ich habe Aliase in meiner .psqlrc-Datei mit Abfragen erstellt, um herauszufinden, welche Indizes hinzugefügt oder entfernt werden sollen. Schauen Sie sich diese bei GitHub an: .psql

Ich benutze häufig: seq_scans und: bigtables und dann \ d table_name, um Details über die Tabelle zu erhalten. Vergessen Sie nicht, die Statistik zurückzusetzen, nachdem Sie einige Änderungen vorgenommen haben. Wählen Sie pg_stat_reset ().

Claes Mogren
quelle
1
Dies sind ausgezeichnete Tipps. Ich habe Ihren Rat befolgt und dann ein Experiment an einer viel größeren Tabelle durchgeführt, die wir verwalten (43 Millionen Zeilen). Die Ergebnisse sind in: dba.stackexchange.com/questions/61084/...
Dr.YSG
1

Ich denke, das, was am wahrscheinlichsten hilft (wenn überhaupt), wäre, product_type als zweite Spalte zum Hauptindex hinzuzufügen. Aber ohne zu wissen, wie viele Zeilen mit jeder der UND-Bedingungen (isoliert) für Ihre typischen / problematischen Abfragen übereinstimmen, können wir nur raten.

Wenn ich mich dem nähere, führe ich als erstes die Abfrage in vereinfachter Form aus, wobei die WHERE-Klausel unter EXPLAIN ANALYZE nur eine Bedingung enthält, die jeweils nacheinander ausgeführt wird. Sehen Sie sich sowohl die geschätzten als auch die tatsächlichen Zeilen für jede Zeile an.

jjanes
quelle
Siehe mein Update oben, aber ich denke, Sie geben mir einen guten Vorsprung. Denken Sie darüber nach, die Indizes zu ordnen, um die die Zeilenausgabe am schnellsten reduziert wird. Ist das richtig?
Dr.YSG