2010-02-10 9 views
10

Ho appena ristrutturato il mio database per utilizzare partitioning in Postgres 8.2. Ora ho un problema con le prestazioni delle query:Interrogazione efficiente della tabella Postgres multi-partizione

SELECT * 
FROM my_table 
WHERE time_stamp >= '2010-02-10' and time_stamp < '2010-02-11' 
ORDER BY id DESC 
LIMIT 100; 

Ci sono 45 milioni di righe nella tabella. Prima del partizionamento, questo utilizza una scansione dell'indice inverso e si interrompe non appena raggiunge il limite.

Dopo il partizionamento (su intervalli time_stamp), Postgres esegue una scansione dell'indice completa della tabella principale e della partizione pertinente e unisce i risultati, li ordina, quindi applica il limite. Questo richiede troppo tempo.

posso risolvere il problema con:

SELECT * FROM (
    SELECT * 
    FROM my_table_part_a 
    WHERE time_stamp >= '2010-02-10' and time_stamp < '2010-02-11' 
    ORDER BY id DESC 
    LIMIT 100) t 
UNION ALL 
SELECT * FROM (
    SELECT * 
    FROM my_table_part_b 
    WHERE time_stamp >= '2010-02-10' and time_stamp < '2010-02-11' 
    ORDER BY id DESC 
    LIMIT 100) t 
UNION ALL 
    ... and so on ... 
ORDER BY id DESC 
LIMIT 100 

Questa corre rapidamente. Le partizioni in cui i timestamp sono fuori intervallo non sono nemmeno incluse nel piano di query.

La mia domanda è: Esiste qualche suggerimento o sintassi che posso utilizzare in Postgres 8.2 per impedire a query-planner di eseguire la scansione dell'intera tabella ma utilizzando ancora una sintassi semplice che si riferisce solo alla tabella principale?

In sostanza, è possibile evitare il fastidio di creare dinamicamente la grande query UNION su ogni partizione che si verifica attualmente?

EDIT: ho constraint_exclusion abilitato (grazie @Vinko Vrsalovic)

+1

8.2? veramente? Prima di fare qualsiasi altra cosa si dovrebbe prendere in considerazione l'aggiornamento a una versione supportata (e corrente) di Postgres (9.2 è quella attuale) –

risposta

3

Hai provato vincolo di esclusione (sezione 5.9.4 del documento aver collegato a)

esclusione vincolo è una query tecnica di ottimizzazione che migliora le prestazioni per le tabelle partizionate definite nella modalità descritta precedente. Come esempio:

SET constraint_exclusion = on; 
SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01'; 

Senza esclusione vincolo, la query sopra sarebbe scandire ciascuna delle partizioni la tabella di misura. Con vincolo esclusione abilitata, il pianificatore esaminerà i vincoli di ogni partizione e cercare di dimostrare che la partizione non deve essere esaminati a causa non poteva contenere le righe che soddisfano della query clausola WHERE. Quando il pianificatore può dimostrarlo, esclude la partizione dal piano di query.

È possibile utilizzare il comando EXPLAIN per mostrare la differenza tra un piano con constraint_exclusion su e un piano con esso off.

+0

Sì, ho attivato l'esclusione di vincoli. Sfortunatamente, la tabella master (che è sempre vuota) viene sempre inclusa nella query in quanto non è possibile applicare un vincolo CHECK ad esso (almeno in 8.2). Ciò significa che nella query sono coinvolte almeno due tabelle –

4

Ho avuto un problema simile a quello che ero in grado di risolvere tramite condizioni di fusione in DOVE. EG: (supponendo che la colonna time_stamp è timestamptz tipo)

WHERE time_stamp >= '2010-02-10'::timestamptz and time_stamp < '2010-02-11'::timestamptz 

Inoltre, assicurarsi che la circostanza CONTROLLO sul tavolo è definito allo stesso modo ... EG: CHECK (time_stamp < '2010-02-10' :: timestamptz)

2

Ho avuto lo stesso problema e si ridusse a due ragioni nel mio caso: colonna

  1. avevo indicizzati di tipo timestamp WITH time zone e vincolo di partizione da questa colonna con tipo timestamp WITHOUT time zone.

  2. Dopo aver risolto i vincoli ANALYZE di tutte le tabelle figlio era necessario.

Edit: un altro po 'di conoscenza - è importante ricordare che l'esclusione vincolo (che permette di PG per saltare la scansione di alcune tabelle, sulla base di criteri di partizionamento) non funziona con, citando: non-immutable function such as CURRENT_TIMESTAMP

Ho avuto richieste con CURRENT_DATE e faceva parte del mio problema.

Problemi correlati