Ordine delle colonne in un indice composto in PostgreSQL (e ordine delle query)


9

Ho una tabella con 50.000 righe. In realtà è una tabella PostGIS.

La query ha 4 parti (1 obbligatoria) (3 Opzionale)

  1. casella di intersezione (un rettangolo geografico) con 4 lat, long (io uso st_intersects) [Obbligatorio]
  2. Intervallo di date (min, max) su un campo data
  3. Tipo di file (un insieme di un massimo di 8 valori di testo) che attualmente utilizza IN (.....) ma se necessario posso creare una tabella temporanea. Vedo che a molte persone non piace IN.
  4. Paese (un valore di testo).

Mi aspetto circa 100 - 4.000 righe restituite

Se creo un indice composto sulla tabella, quale colonna dovrei usare per prima. La grana fine è probabilmente la posizione (i dati sono diffusi in tutto il mondo). Attualmente lo ho come indice GIST.

Gli altri indici sarebbero BTREE.

La mia intuizione dice che usare grana fine, e ovviamente ultimo. Ad esempio, ci sono solo circa 12 tipi di file, quindi sarebbe molto grande per l'indice.

Cosa dicono i guru PostgreSQL e PostGIS (che conoscono gli interni del sistema)?


AGGIORNARE:

Vorrei affinare questa domanda.

  1. Non voglio che nessuno debba fare il lavoro che dovrei fare. Rispetto troppo il tuo tempo. Quindi passerò alla spiegazione dell'analisi più avanti.
  2. Tutto quello che cercavo erano alcuni suggerimenti, consigli e linee guida.
  3. Ho letto questo eccellente post: https://devcenter.heroku.com/articles/postgresql-indexes#managing-and-maintain-indexes sugli indici
  4. Quello che faccio normalmente è creare 4 indici separati (geo-box, nome del paese, tipo_file e data) ma cosa voglio vedere cosa farebbe una query composita.

Dimmi se qualcuno di questi presupposti è sbagliato. (Sono abbastanza nuovo all'idea di indici composti)

  1. L'ordine è importante. Scegli come primo indice quello che ridurrà maggiormente le righe (nel mio caso la posizione (geografia) che è un semplice poligono o poligono farebbe il meglio).
  2. A volte le query salteranno gli indici. Ma se creo una query composta con chiave (# 1, # 2, # 3, # 4), anche se l'utente crea qualcosa che richiede # 1, # 3, il planner utilizzerà comunque la singola query composita, poiché ordinano è mantenuto.
  3. Normalmente creerei tre query BTREE e una GIST (per il tipo di geografia). PostGIS non supporta la creazione di un composto di più tipi di indice. Quindi dovrò usare GIST l'indice composto. Ma ciò non dovrebbe ferire le cose.
  4. Se creo alcuni indici composti o di valore singolo, il planner è abbastanza intelligente da scegliere quello più intelligente .....
  5. Il nome del paese può avere circa 250 valori diversi ed è ovviamente fortemente legato alla posizione (geobox), ma se il prossimo indice migliore per ridurre la dimensione della riga è file_type, dovrei usarlo successivamente. Non mi aspetto che gli utenti utilizzino spesso il Paese o la data nei loro set di query.
  6. Non devo preoccuparmi di creare un indice composto di 4 chiavi aumenterà notevolmente la dimensione dei dati dell'indice. Vale a dire se un indice a una chiave sarebbe il 90% dell'aumento delle prestazioni, non fa male aggiungere altri 3 elementi per renderlo composto. Al contrario, dovrei davvero creare entrambi gli indici. Un indice geografico singolo, e anche un indice composto, e lascia che il pianificatore capisca qual è il migliore, e terrà conto della dimensione della tabella dell'indice.

Ancora una volta, non sto chiedendo a nessuno di progettare la mia soluzione, non mi preoccupo del lavoro degli altri. Ma ho bisogno di cose che la documentazione di PostGreSQL non mi dice dell'implementazione

[Il motivo per cui non ho ancora un risultato EXPLAIN da mostrare è che devo creare questa tabella di righe da 25 KB da una tabella di righe da 24 milioni. Ci vuole più tempo di quanto pensassi. Sto raggruppando le cose in 1.000 gruppi di articoli e lascio che l'utente esegua una query sulla tabella delle righe da 25 KB. Ma la mia prossima domanda riguarderà l'uso dei risultati di quella query per andare alla tabella delle righe MASTER 25M ed estrarre le cose, ed è qui che le prestazioni dell'indice composto colpiranno davvero].


query di esempio di seguito:


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')) ;

SPIEGARE i risultati ANALISI (non ho inserito alcun indice composto e dalla velocità che vedo non so se ne ho bisogno).

"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'))

2
Fornisci la domanda effettiva, per favore.
ypercubeᵀᴹ

"3 opzionale" significa che la query può avere 8 diverse varianti (a seconda che le opzioni 2,3,4 siano attivate o meno)?
ypercubeᵀᴹ

Ci sono 4 componenti AND in WHERE. Su st_intersects è richiesto, gli altri potrebbero essere lì o potrebbero non esserlo. Ma voglio affrontare il caso in cui sono tutti presenti.

2
Ho votato per migrare la domanda su dba.se, questa è una query complessa con condizioni a più intervalli.
ypercubeᵀᴹ

1
Mostra EXPLAIN ANALYZEper la query.
Craig Ringer,

Risposte:


4

Come parte del mio lavoro, mantengo un database PostgreSQL abbastanza grande (circa 120 GB su disco, diverse tabelle da più milioni di righe) e ho raccolto alcuni trucchi su come velocizzare le query. Innanzitutto alcuni commenti sui tuoi presupposti:

  1. Sì, l'ordine è importante, ma è solo il primo ad essere veramente diverso, il resto sono indici di seconda classe.
  2. Non sono sicuro che userà sempre entrambi, suppongo che il pianificatore di query userà il n. 1, quindi farà qualcosa di intelligente con il resto.
  3. Non ho esperienza con GIST.
  4. Sì, aggiungi prima tutti gli indici, vedi cosa viene utilizzato di più e cosa offre le migliori prestazioni.
  5. Vorrei che tu provassi entrambi e misuri ciò che funziona meglio. Prova a riscrivere sql con diverse sottoquery, magari paese e ora in una, quindi unisciti alla query intersect. Non ho notato alcun problema di prestazioni con le clausole IN, purché l'elenco IN non sia lungo migliaia di elementi. La mia ipotesi è che alcune query diverse ottimizzate in modo specifico in base ai criteri di input disponibili forniranno i migliori risultati.
  6. Suggerirei di non creare un indice a 4 vie. Prova a crearne uno e poi controlla le dimensioni, possono diventare davvero enormi. Nella mia esperienza, quattro indici a 1 chiave sono stati quasi veloci come un singolo indice a 4 vie. Un trucco che funziona bene per alcune query specifiche sono gli indici parziali, ovvero qualcosa del genere:

    CREA INDICE SU table_x (chiave1, chiave2, chiave3) DOVE some_x_column = 'XXXX';

Ho creato alias nel mio file .psqlrc con query per aiutare a trovare quali indici aggiungere o rimuovere. Sentiti libero di dare un'occhiata a GitHub: .psql

Uso molto: seq_scans e: bigtables, e quindi \ d table_name per ottenere dettagli sulla tabella. Non dimenticare di ripristinare le statistiche dopo aver apportato alcune modifiche, selezionare pg_stat_reset ();


1
Questi sono consigli eccellenti. Ho seguito il tuo consiglio e poi l'ho usato per fare un esperimento su una tabella molto più grande che manteniamo (43 milioni di righe). I risultati sono disponibili su: dba.stackexchange.com/questions/61084/…
Dr.YSG

1

Penso che la cosa più probabile che possa aiutare (semmai) sarebbe aggiungere product_type come seconda colonna all'indice gist. Ma senza sapere quante righe corrispondono a ciascuna delle condizioni AND (in isolamento) per le tue query tipiche / problematiche, possiamo solo indovinare.

Quando mi avvicino a questo, la prima cosa che faccio è eseguire la query in forma semplificata in cui la clausola WHERE ha solo una condizione, ognuna presa a turno, in EXPLAIN ANALYZE. Guarda sia le righe stimate sia le righe effettive per ognuna.


vedi il mio aggiornamento sopra, ma penso che mi stai dando un buon vantaggio, pensa a ordinare gli indici in base ai quali riduce l'output di riga più velocemente. È giusto?
Dr.YSG
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.