Domanda

Ho un database PostgreSQL con una tabella principale e 2 tabelle figlie.La mia tabella principale:

CREATE TABLE test (
    id serial PRIMARY KEY, 
    date timestamp without time zone
);
CREATE INDEX ON test(date);

Le mie tabelle figlio:

CREATE TABLE test_20150812 (
    CHECK ( date >= DATE '2015-08-12' AND date < DATE '2015-08-13' )
) INHERITS (test);

CREATE TABLE test_20150811 (
    CHECK ( date >= DATE '2015-08-11' AND date < DATE '2015-08-12' )
) INHERITS (test);

CREATE INDEX ON test_20150812(date);
CREATE INDEX ON test_20150811(date);

Quando eseguo query come:

select * from test_20150812 where date > '2015-08-12' order by date desc;

Ritorna molto velocemente (20-30 millisecondi). EXPLAIN produzione:

 Limit  (cost=0.00..2.69 rows=50 width=212)
   ->  Index Scan Backward using test_20150812_date_idx on test_20150812  (cost=0.00..149538.92 rows=2782286 width=212)
         Index Cond: (date > '2015-08-12 00:00:00'::timestamp without time zone)

Tuttavia se eseguo query come:

select * from test where date > '2015-08-12' order by date desc;

Ci vuole molto tempo (10-15 secondi). EXPLAIN produzione:

 Limit  (cost=196687.06..196687.19 rows=50 width=212)
   ->  Sort  (cost=196687.06..203617.51 rows=2772180 width=212)
         Sort Key: public.test.date
         ->  Result  (cost=0.00..104597.24 rows=2772180 width=212)
               ->  Append  (cost=0.00..104597.24 rows=2772180 width=212)
                     ->  Seq Scan on test  (cost=0.00..0.00 rows=1 width=1857)
                           Filter: (date > '2015-08-12 00:00:00'::timestamp without time zone)
                     ->  Seq Scan on test_20150812 test  (cost=0.00..104597.24 rows=2772179 width=212)
                           Filter: (date > '2015-08-12 00:00:00'::timestamp without time zone)

constraint_exclusion è impostato per ON nel mio postgresql.conf.Pertanto dovrebbe essere eseguito solo su test_20150812.

Vedo che, se una query viene eseguita sulla tabella principale, gli indici non vengono mai utilizzati.Come posso migliorarlo?Voglio fare tutte le mie domande sulla mia tabella principale.Quando si esegue una query per una data specifica non mi aspetto alcuna differenza di prestazioni tra l'esecuzione di query sulla tabella principale o sulla tabella figlio.

È stato utile?

Soluzione

"data"

Non chiamare il tuo timestamp colonna "data", è molto fuorviante.Meglio ancora, non utilizzare affatto il nome del tipo di base "data" come identificatore, è soggetto a errori, porta a messaggi di errore confusi ed è un parola riservata in SQL standard.Dovrebbe essere qualcosa del tipo:

CREATE TABLE test (
  id serial PRIMARY KEY
, ts timestamp NOT NULL  -- also adding NOT NULL constraint
);
CREATE INDEX ON test(ts);

Avvertenze

Fare attenzione a questo avvertimento con l'esclusione del vincolo:

L'esclusione dei vincoli funziona solo quando la query WHERE clausola contiene costanti (o parametri forniti esternamente).Ad esempio, un confronto con una funzione non immutabile come CURRENT_TIMESTAMPNon può essere ottimizzato, poiché il pianificatore non può sapere in quale partizione potrebbe cadere il valore della funzione in fase di esecuzione.

Grassetto, enfasi mia. Questa l'hai schivata, ma con la tua configurazione confusa potresti inciamparci abbastanza presto.

Inoltre, dal momento che hai quotidiano partizioni:

Tutti i vincoli su tutte le partizioni della tabella principale vengono esaminati durante l'esclusione dei vincoli, quindi è probabile che un gran numero di partizioni aumenti considerevolmente il tempo di pianificazione delle query.Il partizionamento usando queste tecniche funzionerà bene con fino a forse un centinaio di partizioni;non provare a utilizzare molte migliaia di partizioni.

L'enfasi è forte, mia.Se la tua durata è superiore a un paio di mesi, prova invece le partizioni settimanali o mensili.

Mancata corrispondenza nei predicati

La tua condizione di controllo:

CHECK ( date >= DATE '2015-08-12' AND date < DATE '2015-08-13' )

Ma la tua query ha la condizione:

where date > '2015-08-12' order by date desc;  -- should be: >=

Ciò lascia una leggera discrepanza (probabilmente errato!) e costringe Postgres a ricontrollare la condizione.Non va bene, ma non posso nemmeno rispondere alla tua domanda.

Utilizzo >=, e creare la colonna NOT NULL o aggiungere NULLS LAST alla dichiarazione:

WHERE ts >= '2015-08-12' ORDER BY ts DESC;

...e fai corrispondere l'indice.

Impuro CHECK vincolo

IL CHECK i vincoli vengono salvati con date costanti invece di timestamp costanti.Dovrebbe essere qualcosa del tipo:

CHECK (ts >= timestamp '2015-08-11' AND ts < timestamp '2015-08-12');

Esclusione di vincoli

Scrivi:

constraint_exclusion è impostato per ON nel mio postgresql.conf.Pertanto dovrebbe essere eseguito solo su test_20150812.

Come puoi vedere solo nel piano di query test E test_20150812 vengono scansionati, ma non test_20150811.Quindi:l'esclusione dei vincoli funziona correttamente, nonostante tutte le tue deviazioni.Questa è solo un'altra strada sbagliata.

Ha vinto molte battaglie, ma non la guerra

Dopo aver ripulito tutto questo, vedo a scansione dell'indice bitmap per la tabella figlio invece della scansione seq.Ancora più lento di una query solo sulla tabella figlio.Ciò è ovviamente dovuto al fatto che anche la tabella padre stessa può avere righe corrispondenti, che devono essere ordinate con il resto, quindi il risultato non può essere semplicemente letto dall'indice.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a dba.stackexchange
scroll top