Vincolo di partizione non utilizzato per join che coinvolgono tabelle partizionate da timestamp


11

Ho una struttura di tabella partizionata come:

CREATE TABLE measurements (
    sensor_id bigint,
    tx timestamp,
    measurement int
);

CREATE TABLE measurements_201201(
    CHECK (tx >= '2012-01-01 00:00:00'::timestamp without time zone 
       AND tx < ('2012-01-01 00:00:00'::timestamp without time zone + '1 mon'::interval))    
)INHERITS (measurements);
CREATE INDEX ON measurements_201201(sensor_id);
CREATE INDEX ON measurements_201201(tx);
CREATE INDEX ON measurements_201201(sensor_id, tx);
....

E così via. Ogni tabella ha circa 20 milioni di righe.

Se eseguo una query per un campione di sensori e un campione di timestamp nella WHEREclausola, il piano di query mostra le tabelle corrette selezionate e gli indici utilizzati, ad esempio:

SELECT *
FROM measurements
INNER JOIN sensors TABLESAMPLE BERNOULLI (0.01) USING (sensor_id)
WHERE tx BETWEEN '2015-01-04 05:00' AND '2015-01-04 06:00' 
    OR tx BETWEEN '2015-02-04 05:00' AND '2015-02-04 06:00' 
    OR tx BETWEEN '2014-03-05 05:00' AND '2014-04-07 06:00' ;

Tuttavia, se utilizzo un CTE o inserisco i valori di data / ora in una tabella (non mostrato, anche con gli indici nella tabella temporanea).

WITH sensor_sample AS(
    SELECT sensor_id, start_ts, end_ts
    FROM sensors TABLESAMPLE BERNOULLI (0.01)
    CROSS JOIN (VALUES (TIMESTAMP '2015-01-04 05:00', TIMESTAMP '2015-01-04 06:00'),
        (TIMESTAMP '2015-02-04 05:00', TIMESTAMP '2015-02-04 06:00'),
        (TIMESTAMP  '2014-03-05 05:00', '2014-04-07 06:00') ) tstamps(start_ts, end_ts)
)

Qualcosa di simile al sotto

SET constraint_exclusion = on;
SELECT * FROM measurements
INNER JOIN sensor_sample USING (sensor_id)
WHERE tx BETWEEN start_ts AND end_ts

Esegue una scansione dell'indice su ogni tabella. Che è ancora relativamente veloce, ma con una crescente complessità delle query, questo può trasformarsi in scansioni seq che finiranno per essere molto lente per il recupero di ~ 40K righe da un sottoinsieme limitato di tabelle partizionate (4-5 di 50).

Sono interessato che qualcosa di simile a questo è il problema.

Per espressioni non banali devi ripetere la condizione più o meno alla lettera nelle query per far capire al pianificatore di query Postgres che può fare affidamento sul vincolo CHECK. Anche se sembra ridondante!

Come posso migliorare il partizionamento e la struttura delle query per ridurre la probabilità di eseguire scansioni seq su tutti i miei dati?


1
grande domanda - ma sarebbe ancora meglio se
incollassi i

Risposte:


1

L'esclusione basata sui vincoli [CBE] viene eseguita nelle prime fasi della pianificazione della query, subito dopo che la query viene analizzata, mappata alle relazioni effettive e riscritta. ( interni , fase di pianificazione / ottimizzazione)

Il planner non può assumere alcun contenuto della tabella "sensor_sample".

Quindi, a meno che tu non abbia valori hardcoded nella query, il planner non escluderà "partizioni".

Immagino cosa succede con la variante CTE ... il planner è limitato perché usi TABLESAMPLE e l'intera sottoquery può essere considerata volatile anche se i letterali nella sottoquery sono statici. ( è solo una mia ipotesi, non sono esperto di codice planner )

Sul lato positivo, la scansione dell'indice con risultato negativo è incredibilmente veloce. (scansione di una sola pagina al massimo!) quindi a meno che tu non abbia più di 10000 partizioni, non mi preoccuperei.

Quindi, per rispondere direttamente alla tua domanda:

  • Non è possibile migliorare molto di più questa struttura di dati.

  • Per quanto riguarda le scansioni dell'indice - sono economiche;

  • Per quanto riguarda le scansioni sequenziali, quando possibile vengono evitate, come si vede dai propri esempi.

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.