Hola a todos Tengo un problema con mi consulta de base de datos PostgreSQL y me pregunto si alguien puede ayudar. En algunos escenarios, mi consulta parece ignorar el índice que he creado que se utiliza para unir las dos tablas data
y data_area
. Cuando esto sucede, utiliza una exploración secuencial y da como resultado una consulta mucho más lenta.
Escaneo secuencial (~ 5 minutos)
Unique (cost=15368261.82..15369053.96 rows=200 width=1942) (actual time=301266.832..301346.936 rows=153812 loops=1)
CTE data
-> Bitmap Heap Scan on data (cost=6086.77..610089.54 rows=321976 width=297) (actual time=26.286..197.625 rows=335130 loops=1)
Recheck Cond: (datasetid = 1)
Filter: ((readingdatetime >= '1920-01-01 00:00:00'::timestamp without time zone) AND (readingdatetime <= '2013-03-11 00:00:00'::timestamp without time zone) AND (depth >= 0::double precision) AND (depth <= 99999::double precision))
-> Bitmap Index Scan on data_datasetid_index (cost=0.00..6006.27 rows=324789 width=0) (actual time=25.462..25.462 rows=335130 loops=1)
Index Cond: (datasetid = 1)
-> Sort (cost=15368261.82..15368657.89 rows=158427 width=1942) (actual time=301266.829..301287.110 rows=155194 loops=1)
Sort Key: data.id
Sort Method: quicksort Memory: 81999kB
-> Hash Left Join (cost=15174943.29..15354578.91 rows=158427 width=1942) (actual time=300068.588..301052.832 rows=155194 loops=1)
Hash Cond: (data_area.area_id = area.id)
-> Hash Join (cost=15174792.93..15351854.12 rows=158427 width=684) (actual time=300066.288..300971.644 rows=155194 loops=1)
Hash Cond: (data.id = data_area.data_id)
-> CTE Scan on data (cost=0.00..6439.52 rows=321976 width=676) (actual time=26.290..313.842 rows=335130 loops=1)
-> Hash (cost=14857017.62..14857017.62 rows=25422025 width=8) (actual time=300028.260..300028.260 rows=26709939 loops=1)
Buckets: 4194304 Batches: 1 Memory Usage: 1043357kB
-> Seq Scan on data_area (cost=0.00..14857017.62 rows=25422025 width=8) (actual time=182921.056..291687.996 rows=26709939 loops=1)
Filter: (area_id = ANY ('{28,29,30,31,32,33,25,26,27,18,19,20,21,12,13,14,15,16,17,34,35,1,2,3,4,5,6,22,23,24,7,8,9,10,11}'::integer[]))
-> Hash (cost=108.49..108.49 rows=3349 width=1258) (actual time=2.256..2.256 rows=3349 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 584kB
-> Seq Scan on area (cost=0.00..108.49 rows=3349 width=1258) (actual time=0.007..0.666 rows=3349 loops=1)
Total runtime: 301493.379 ms
Escaneo de índice (~ 3 segundos) ( en explicar.depesz.com )
Unique (cost=17352256.47..17353067.50 rows=200 width=1942) (actual time=3603.303..3681.619 rows=153812 loops=1)
CTE data
-> Bitmap Heap Scan on data (cost=6284.60..619979.56 rows=332340 width=297) (actual time=26.201..262.314 rows=335130 loops=1)
Recheck Cond: (datasetid = 1)
Filter: ((readingdatetime >= '1920-01-01 00:00:00'::timestamp without time zone) AND (readingdatetime <= '2013-03-11 00:00:00'::timestamp without time zone) AND (depth >= 0::double precision) AND (depth <= 99999::double precision))
-> Bitmap Index Scan on data_datasetid_index (cost=0.00..6201.51 rows=335354 width=0) (actual time=25.381..25.381 rows=335130 loops=1)
Index Cond: (datasetid = 1)
-> Sort (cost=17352256.47..17352661.98 rows=162206 width=1942) (actual time=3603.302..3623.113 rows=155194 loops=1)
Sort Key: data.id
Sort Method: quicksort Memory: 81999kB
-> Hash Left Join (cost=1296.08..17338219.59 rows=162206 width=1942) (actual time=29.980..3375.921 rows=155194 loops=1)
Hash Cond: (data_area.area_id = area.id)
-> Nested Loop (cost=0.00..17334287.66 rows=162206 width=684) (actual time=26.903..3268.674 rows=155194 loops=1)
-> CTE Scan on data (cost=0.00..6646.80 rows=332340 width=676) (actual time=26.205..421.858 rows=335130 loops=1)
-> Index Scan using data_area_pkey on data_area (cost=0.00..52.13 rows=1 width=8) (actual time=0.006..0.008 rows=0 loops=335130)
Index Cond: (data_id = data.id)
Filter: (area_id = ANY ('{28,29,30,31,32,33,25,26,27,18,19,20,21,12,13,14,15,16,17,34,35,1,2,3,4,5,6,22,23,24,7,8,9,10,11}'::integer[]))
-> Hash (cost=1254.22..1254.22 rows=3349 width=1258) (actual time=3.057..3.057 rows=3349 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 584kB
-> Index Scan using area_primary_key on area (cost=0.00..1254.22 rows=3349 width=1258) (actual time=0.012..1.429 rows=3349 loops=1)
Total runtime: 3706.630 ms
Estructura de la mesa
Esta es la estructura de la data_area
tabla para la tabla. Puedo proporcionar las otras tablas si es necesario.
CREATE TABLE data_area
(
data_id integer NOT NULL,
area_id integer NOT NULL,
CONSTRAINT data_area_pkey PRIMARY KEY (data_id , area_id ),
CONSTRAINT data_area_area_id_fk FOREIGN KEY (area_id)
REFERENCES area (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT data_area_data_id_fk FOREIGN KEY (data_id)
REFERENCES data (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
);
CONSULTA
WITH data AS (
SELECT *
FROM data
WHERE
datasetid IN (1)
AND (readingdatetime BETWEEN '1920-01-01' AND '2013-03-11')
AND depth BETWEEN 0 AND 99999
)
SELECT *
FROM (
SELECT DISTINCT ON (data.id) data.id, *
FROM
data,
data_area
LEFT JOIN area ON area_id = area.id
WHERE
data_id = data.id
AND area_id IN (28,29,30,31,32,33,25,26,27,18,19,20,21,12,13,14,15,16,17,34,35,1,2,3,4,5,6,22,23,24,7,8,9,10,11)
) as s;
Devuelve 153812
filas. Hizo set enable_seqscan= false;
para deshabilitar la exploración secuencial y obtener el resultado del índice.
Intenté hacer un ANALYSE
en la base de datos y aumentar las estadísticas recopiladas en las columnas utilizadas en la consulta, pero nada parece ayudar.
¿Podría alguien difundir y aclarar esto o sugerir algo más que debería intentar?
fuente
FROM data, data_area
)? A primera vista, usar DISTINCT ON sin una cláusula ORDER BY parece ser una mala idea.Respuestas:
Observe esta línea:
Si calcula el costo total, considerando los bucles, lo es
52.3 * 335130 = 17527299
. Esto es mayor que 14857017.62 para laseq_scan
alternativa. Es por eso que no usa el índice.Por lo tanto, el optimizador está sobreestimando el costo de la exploración del índice. Supongo que sus datos se ordenan en el índice (ya sea debido a un índice agrupado o a cómo se cargó) y / o tiene mucha memoria caché y / o un buen disco rápido. Por lo tanto, hay pocas E / S aleatorias.
También debe comprobar el
correlation
enpg_stats
, que es utilizado por el optimizador para evaluar la agrupación cuando se calcula el costo del índice, y, finalmente, tratar de cambiarrandom_page_cost
ycpu_index_tuple_cost
, para que coincida con su sistema.fuente
52.13
, no52.3
, lo que resultaría en 17470326.9 (aún más grande que el seq_scan)Su CTE en realidad no hace nada más que 'externalizar' algunas
WHERE
condiciones, la mayoría de ellas con un aspecto equivalenteWHERE TRUE
. Dado que los CTE generalmente están detrás de una valla de optimización (lo que significa que está optimizado por sí solo), pueden ayudar mucho con ciertas consultas. En este caso, sin embargo, esperaría exactamente el efecto contrario.Lo que intentaría es reescribir la consulta para que sea lo más simple posible:
y luego verifique si el índice se usa o no. Todavía es muy posible que no necesite todas las columnas de salida (al menos las dos columnas de la tabla de unión son superfluas).
Informe y díganos qué versión de PostgreSQL usa.
fuente
SET enable_nestloop=off
antes de ejecutar la consulta?Para los seguidores, tuve un problema similar que era como
select * from table where bigint_column between x and y and mod(bigint_column, 10000) == z
El problema era que mi bigint_column "entre x e y" tenía un índice, pero mi consulta era básicamente "todas las filas" en esa tabla, por lo que no estaba usando el índice [ya que tenía que escanear toda la tabla de todos modos] pero estaba haciendo una exploración secuencial seq_scan. Una solución para mí fue crear un nuevo índice para el lado "mod" de la ecuación, de modo que pudiera usarlo en una expresión .
fuente