Escaneos de índice lentos en una tabla grande


12

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_idclave 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.


1
Díganos cómo se ve su tabla, qué índices tiene y la difusión de datos.
Colin 't Hart

Agregué la información adicional que solicitó. No sé si me perdí algo.
Exelian

2
Extraño: su explicación analiza muestra prop_time_idx, pero la definición de la tabla muestra entry_prop_id_timestamp_idx. ¿Es este el mismo índice? Por favor, arregla.
Colin 't Hart

Si se refiere por "las estimaciones de costos parecen ser un factor 4 veces mayor" al hecho de que los números de costos son aproximadamente 4 veces los del tiempo real , entonces tenga en cuenta que los dos no tienen nada que ver entre sí. El costo es solo una estimación, lo que ayuda al optimizador de consultas a elegir el mejor plan. Fuera de este contexto, generalmente es un valor sin sentido.
dezso

1
¿Cuánto porcentaje de la tabla representa su rango de fechas (sin tener en cuenta los valores para 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 ( propen su caso) también suelen ser redundantes.
Colin 't Hart

Respuestas:


10

Su tabla es grande , y también lo es cualquier índice que abarque toda la tabla. Asumiendo que:

  • solo timestamp = now()se ingresan datos nuevos (con )
  • las filas existentes no se modifican ni se eliminan.
  • tiene datos desde el 01-01-2012 pero las consultas son predominantemente en el año actual (?)

Sugeriría un índice parcial de varias columnas (¡cubriendo!) :

CREATE INDEX ON energy_energyentry (prop_id, "timestamp", value)
WHERE "timestamp" >= '2014-01-01 0:0';  -- adapt to your needs

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:

SELECT sum(value) AS sum_value
FROM   energy_energyentry
WHERE  prop_id = 82411 
AND   "timestamp" > '2014-06-11 0:0' 
AND   "timestamp" < '2014-11-11 0:0'
AND   "timestamp" >= '2014-01-01 0:0'; -- seems redundant, but may be needed

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 CLUSTERy FILLFACTOR, 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:


Ahora que Postgres admite índices BRIN, ¿sería útil aquí? Planeo almacenar alrededor de 140 millones de filas en datos en postgres, ¿es BRIN el índice correcto para usar en una tabla tan grande?
Arya

2

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.


Agregar el valor puede ser interesante de hecho, echaré un vistazo si eso acelerará las cosas. ¿Tiene alguna sugerencia para la configuración de vacío o la documentación que puedo ver?
Exelian
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.