PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Slow LEFT JOIN su CTE con intervalli di tempo

Prima la correttezza :Sospetto un bug nella tua query:

 LEFT JOIN historical_ohlcv ohlcv ON ohlcv.time_open >= g.start_time
                                 AND ohlcv.time_close < g.end_time

A differenza della mia risposta di riferimento, ti unisci a un intervallo di tempo :(time_open, time_close] . Il modo in cui lo fai esclude le righe nella tabella in cui l'intervallo attraversa i bordi del bucket. Solo gli intervalli completamente contenuti in un singolo bucket. Non credo sia previsto?

Una semplice soluzione sarebbe decidere l'appartenenza al bucket in base a time_open (o time_close ) solo. Se vuoi continuare a lavorare con entrambi, devi definire esattamente come gestire gli intervalli che si sovrappongono a più bucket.

Inoltre, stai cercando max(high) per bucket, che è di natura diversa da count(*) nella mia risposta di riferimento.

E i tuoi secchi sono semplici intervalli all'ora?

Allora possiamo semplificare radicalmente. Lavorare solo con time_open :

SELECT date_trunc('hour', time_open) AS hour, max(high) AS max_high
FROM   historical_ohlcv
WHERE  exchange_symbol = 'BINANCE'
AND    symbol_id = 'ETHBTC'
AND    time_open >= now() - interval '5 months'  -- frame_start
AND    time_open <  now()                        -- frame_end
GROUP  BY 1
ORDER  BY 1;

Correlati:

  • Ricampiona i dati delle serie temporali

È difficile parlare di un'ulteriore ottimizzazione delle prestazioni mentre le basi non sono chiare. E avremmo bisogno di più informazioni.

Sono WHERE condizioni variabili?
Quanti valori distinti in exchange_symbol e symbol_id ?
Media dimensione della riga? Cosa ottieni per:

SELECT avg(pg_column_size(t)) FROM historical_ohlcv t TABLESAMPLE SYSTEM (0.1);

La tabella è di sola lettura?

Supponendo che filtri sempre su exchange_symbol e symbol_id e i valori sono variabili, la tabella è di sola lettura o l'autovacuum può tenere il passo con il carico di scrittura in modo da poter sperare in scansioni solo indice, è meglio avere un indice multicolonna su (exchange_symbol, symbol_id, time_open, high DESC) per supportare questa domanda. Colonne dell'indice in questo ordine. Correlati:

  • Indice multicolonna e performance

A seconda della distribuzione dei dati e di altri dettagli, un LEFT JOIN LATERAL la soluzione potrebbe essere un'altra opzione. Correlati:

  • Come trovare una media dei valori per gli intervalli di tempo in postgres
  • Ottimizza la query GROUP BY per recuperare l'ultimo record per utente

A parte tutto questo, tu EXPLAIN plan mostra alcuni molto stime sbagliate :

  • https://explain.depesz.com/s/E5yI

Stai usando una corrente versione di Postgres? Potrebbe essere necessario lavorare sulla configurazione del server o almeno impostare obiettivi statistici più elevati su colonne pertinenti e impostazioni di autovacuum più aggressive per il tavolo grande. Correlati:

  • Impedisci a PostgreSQL di scegliere a volte un piano di query errato
  • Autovacuum aggressivo su PostgreSQL