Tengo una consulta relativamente simple en una tabla con 1.5M filas:
SELECT mtid FROM publication
WHERE mtid IN (9762715) OR last_modifier=21321
LIMIT 5000;
EXPLAIN ANALYZE
salida:
Limit (cost=8.84..12.86 rows=1 width=8) (actual time=0.985..0.986 rows=1 loops=1) -> Bitmap Heap Scan on publication (cost=8.84..12.86 rows=1 width=8) (actual time=0.984..0.985 rows=1 loops=1) Recheck Cond: ((mtid = 9762715) OR (last_modifier = 21321)) -> BitmapOr (cost=8.84..8.84 rows=1 width=0) (actual time=0.971..0.971 rows=0 loops=1) -> Bitmap Index Scan on publication_pkey (cost=0.00..4.42 rows=1 width=0) (actual time=0.295..0.295 rows=1 loops=1) Index Cond: (mtid = 9762715) -> Bitmap Index Scan on publication_last_modifier_btree (cost=0.00..4.42 rows=1 width=0) (actual time=0.674..0.674 rows=0 loops=1) Index Cond: (last_modifier = 21321) Total runtime: 1.027 ms
Hasta ahora todo bien, rápido y utiliza los índices disponibles.
Ahora, si modifico una consulta solo un poco, el resultado será:
SELECT mtid FROM publication
WHERE mtid IN (SELECT 9762715) OR last_modifier=21321
LIMIT 5000;
El EXPLAIN ANALYZE
resultado es:
Limit (cost=0.01..2347.74 rows=5000 width=8) (actual time=2735.891..2841.398 rows=1 loops=1) -> Seq Scan on publication (cost=0.01..349652.84 rows=744661 width=8) (actual time=2735.888..2841.393 rows=1 loops=1) Filter: ((hashed SubPlan 1) OR (last_modifier = 21321)) SubPlan 1 -> Result (cost=0.00..0.01 rows=1 width=0) (actual time=0.001..0.001 rows=1 loops=1) Total runtime: 2841.442 ms
No tan rápido, y usando el escaneo seq ...
Por supuesto, la consulta original ejecutada por la aplicación es un poco más compleja e incluso más lenta, y por supuesto, el original generado por hibernación no lo es (SELECT 9762715)
, ¡pero la lentitud está ahí incluso para eso (SELECT 9762715)
! La consulta es generada por hibernate, por lo que es un gran desafío cambiarlas, y algunas características no están disponibles (por ejemplo, UNION
no está disponible, lo que sería rápido).
Las preguntas
- ¿Por qué no se puede usar el índice en el segundo caso? ¿Cómo podrían ser utilizados?
- ¿Puedo mejorar el rendimiento de las consultas de otra manera?
Pensamientos adicionales
Parece que podríamos usar el primer caso haciendo un SELECT manualmente y luego colocando la lista resultante en la consulta. Incluso con 5000 números en la lista IN () es cuatro veces más rápido que la segunda solución. Sin embargo, parece INCORRECTO (también, podría ser 100 veces más rápido :)). Es completamente incomprensible por qué el planificador de consultas utiliza un método completamente diferente para estas dos consultas, por lo que me gustaría encontrar una mejor solución para este problema.
(SELECT 9762715)
.
(SELECT 9762715)
. A la pregunta de hibernación: podría hacerse, pero requiere una reescritura de código seria, ya que tenemos consultas de criterios de hibernación definidas por el usuario que se traducen sobre la marcha. Así que esencialmente estaríamos modificando la hibernación, que es una gran empresa con muchos posibles efectos secundarios.
JOIN
lugar delIN ()
? Además, ¿hapublication
sido analizado recientemente?