Query PostgreSQL semplice molto lenta su RDS
-
11-12-2019 - |
Domanda
Mi sembra che le query siano molto lente su un dispositivo RDS di medie dimensioni (db.m3.medium, ram da 3,7 GB).
Questo è su una tabella di 4.152.928 righe.
select sum(some_field) c
from pages
where pages.some_id=123
and pages.first_action_at > '2014-01-01 00:00:00 +1000'
Durata totale:45031 ms.
Localmente ho circa 1,1 milioni di righe e la stessa query richiede circa 450 ms.
Ecco il piano di query, da spiegare:
Aggregate (cost=475640.59..475640.60 rows=1 width=4)
-> Seq Scan on pages (cost=0.00..475266.07 rows=149809 width=4)
Filter: ((first_action_at > '2014-01-01 00:00:00'::timestamp without time zone)
AND (some_id = 447))
Ecco la risposta di spiegare analizzare:
Aggregate (cost=475641.74..475641.76 rows=1 width=4) (actual time=42419.717..42419.718 rows=1 loops=1)
-> Seq Scan on pages (cost=0.00..475267.22 rows=149810 width=4) (actual time=0.013..42265.908 rows=141559 loops=1)
Filter: ((first_action_at > '2014-01-01 00:00:00'::timestamp without time zone) AND (some_id = 447))
Rows Removed by Filter: 4011369
Durata totale:42419,772 ms
Per riferimento, 141559 righe fanno parte di sum().
Gli indici attuali che ho sono:
:some_id
:some_id, :first_action_at
work_mem
era precedentemente impostato su 1 mb (impostazione predefinita RDS).L'ho appena cambiato in 18 mb.
Modificare:Sembra che si risolva aumentando work_mem
oltre ad aver aggiunto il secondo indice sopra, la velocità è ora intorno agli 800 ms.
Soluzione
Indice corrispondente
Dopo aver riletto la tua domanda, mi sono reso conto che non stai utilizzando Amazon Redshift, ma Amazon RDS, che sembra eseguire almeno Postgres incontaminato secondo la documentazione:
Amazon RDS supporta le istanze DB che eseguono diverse versioni di PostgreSQL.Attualmente supportiamo le versioni PostgreSQL 9.3.1, 9.3.2 e 9.3.3.
Ciò significherebbe che lo hai fatto scansioni del solo indice A tua disposizione.Se soddisfi alcune precondizioni (sostanzialmente se vacuum
può tenere il passo con le operazioni di scrittura) e if some_field
non viene aggiornato spesso e ragionevolmente piccolo (che sembra essere il caso di una colonna numerica), l'indice perfetto includerebbe some_field
in ultima posizione (es @zerkms menzionato per la prima volta):
CREATE INDEX ON pages(some_id, first_action_at, some_field);
Notare che some_id
dovrebbe venire Prima first_action_at
, perché in genere è più efficiente avere prima le colonne con controlli di uguaglianza e poi gli intervalli.Dettagli:
Indice e performance a più colonne
Se non vedi "scansione solo indice" in EXPLAIN ANALYZE
, l'ultima colonna è solo una zavorra ed è meglio lasciarla via:
CREATE INDEX ON pages(some_id, first_action_at);
(Come hai fatto adesso, secondo l'aggiornamento della tua domanda.)
In ogni caso, un altro indice su just (some_id)
offre solo molto poco su questo indice a più colonne:
Un indice composito è utile anche per le query sul primo campo?
Configurazione del server
Tutti i soliti consigli per query lente e corretta configurazione del server si applica e a work_mem
l'impostazione di 1 MB è troppo bassa per un DB con milioni di righe.Ma questa particolare impostazione non dovrebbe essere cruciale per questa particolare query, poiché work_mem
È (per documentazione):
memoria da utilizzare per operazioni di ordinamento interno e tabelle hash.
Nessuno dei due si applica qui.