Al usar PostgreSQL 9.2, tengo problemas con las consultas lentas en una tabla relativamente grande (más de 200 millones de filas). No estoy intentando nada loco, solo agrego valores históricos. A continuación se muestra la consulta y el resultado del plan de consulta.
El diseño de mi mesa:
Table "public.energy_energyentry"
Column | Type | Modifiers
-----------+--------------------------+-----------------------------------------------------------------
id | integer | not null default nextval('energy_energyentry_id_seq'::regclass)
prop_id | integer | not null
timestamp | timestamp with time zone | not null
value | double precision | not null
Indexes:
"energy_energyentry_pkey" PRIMARY KEY, btree (id)
"energy_energyentry_prop_id" btree (prop_id)
"energy_energyentry_prop_id_timestamp_idx" btree (prop_id, "timestamp")
Foreign-key constraints:
"energy_energyentry_prop_id_fkey" FOREIGN KEY (prop_id) REFERENCES gateway_peripheralproperty(id) DEFERRABLE INITIALLY DEFERRED
Los datos van desde 2012-01-01 hasta ahora, con nuevos datos que se agregan constantemente. Hay alrededor de 2.2k valores distintos en la prop_id
clave externa, distribuidos de manera uniforme.
Noto que las estimaciones de las filas no están muy lejos, pero las estimaciones de costos parecen mayores en un factor 4x. Esto probablemente no sea un problema, pero ¿hay algo que pueda hacer al respecto?
Espero que el problema sea el acceso al disco, ya que la tabla no está en la memoria todo el tiempo.
EXPLAIN ANALYZE
SELECT SUM("value")
FROM "energy_energyentry"
WHERE
"prop_id"=82411
AND "timestamp">'2014-06-11'
AND "timestamp"<'2014-11-11'
;
Aggregate (cost=214481.45..214481.46 rows=1 width=8) (actual time=51504.814..51504.814 rows=1 loops=1) -> Index Scan using energy_energyentry_prop_id_timestamp_idx on energy_energyentry (cost=0.00..214434.08 rows=18947 width=8) (actual time=136.030..51488.321 rows=13578 loops=1) Index Cond: ((prop_id = 82411) AND ("timestamp" > '2014-06-11 00:00:00+00'::timestamp with time zone) AND ("timestamp" < '2014-11-11 00:00:00+00'::timestamp with time zone)) Total runtime: 51504.841 ms
¿Alguna sugerencia de cómo hacer esto más rápido?
También estoy bien con solo escuchar que no hice nada extraño.
prop_time_idx
, pero la definición de la tabla muestraentry_prop_id_timestamp_idx
. ¿Es este el mismo índice? Por favor, arregla.prop
)? Si solo un pequeño porcentaje, tal vez un índice en("timestamp", prop)
sería mejor. Los índices múltiples con las mismas columnas iniciales (prop
en su caso) también suelen ser redundantes.Respuestas:
Su tabla es grande , y también lo es cualquier índice que abarque toda la tabla. Asumiendo que:
timestamp = now()
se ingresan datos nuevos (con )Sugeriría un índice parcial de varias columnas (¡cubriendo!) :
Solo incluya el rango de tiempo que se consulta regularmente. La efectividad se deteriora con el tiempo con nuevas entradas. Recrea el índice de vez en cuando. (Es posible que deba adaptar sus consultas). Consulte la respuesta vinculada a continuación.
El último valor de columna solo se incluye para obtener escaneos de solo índice de esto. La configuración agresiva de vacío automático puede ayudar al mantener actualizado el mapa de visibilidad, como @jjanes ya mencionado .
El índice parcial debería caber en la RAM más fácilmente y permanecer allí por más tiempo.
Es posible que deba incluir esto
WHERE
condición en las consultas para que el planificador entienda que el índice es aplicable a la consulta, como:Dado que su consulta suma muchas filas (
rows=13578
), esto llevará algún tiempo, incluso con un escaneo de solo índice. Sin embargo, no debería estar cerca de 50 segundos. Menos de un segundo en cualquier hardware medio decente.Relacionado (pero ignore
CLUSTER
yFILLFACTOR
, ambos son irrelevantes si puede obtener escaneos de solo índice de esto) :Aparte:
dado que actualmente tiene un índice activado
(prop_id, "timestamp")
, el índice adicional solo(prop_id)
puede costar más de lo que vale:fuente
Si realiza el índice en (prop_id, "marca de tiempo", "valor"), entonces podría usar una exploración de solo índice para calcular el valor sin tener que visitar la tabla. Esto podría ahorrar mucho acceso aleatorio al disco.
Para obtener el mayor beneficio, debe ser agresivo al aspirar la mesa. La configuración predeterminada de autovac no es lo suficientemente agresiva para las tablas de solo inserción en las que desea admitir eficientemente escaneos de solo índice.
fuente