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.

È stato utile?

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.

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