Saltar al contenido

La consulta de PostgreSQL es muy lenta cuando se agrega una subconsulta

Solución:

El núcleo del problema se vuelve obvio aquí:

Seq Scan en la publicación (costo = 0.01..349652.84 filas = 744661 ancho = 8) (tiempo real = 2735.888..2841.393 filas = 1 bucles = 1)

Postgres estimados para devolver 744661 filas mientras, de hecho, resulta ser una sola fila. Si Postgres no sabe mejor qué esperar de la consulta, no puede planificar mejor. Necesitaríamos ver la consulta real oculta detrás (SELECT 9762715) – y probablemente también conozca la definición de la tabla, restricciones, cardinalidades y distribución de datos. Obviamente, Postgres no puede predecir cómo pocos Las filas serán devueltas por él. Puede haber formas de reescribir la consulta, dependiendo de lo que es.

Si tu saber que la subconsulta nunca puede devolver más de n filas, puede decirle a Postgres usando:

SELECT mtid
FROM   publication
WHERE  mtid IN (SELECT ... LIMIT n) --  OR last_modifier=21321
LIMIT  5000;

Si norte es lo suficientemente pequeño, Postgres cambiará a escaneos de índice (mapa de bits). Sin embargo, eso solo funciona para el caso simple. Deja de funcionar al agregar un OR condición: el planificador de consultas actualmente no puede hacer frente a eso.

Rara vez uso IN (SELECT ...) para empezar. Por lo general, existe una mejor manera de implementar lo mismo, a menudo con una EXISTS semi-unión. A veces con un (LEFT) JOIN (LATERAL) …

La solución obvia sería utilizar UNION, pero lo descartaste. No puedo decir más sin conocer la subconsulta real y otros detalles relevantes.

Mi colega ha encontrado una manera de cambiar la consulta para que necesite una reescritura simple y haga lo que debe hacer, es decir, hacer la subselección en un paso y luego realizar las operaciones adicionales en el resultado:

SELECT mtid FROM publication 
WHERE 
  mtid = ANY( (SELECT ARRAY(SELECT 9762715))::bigint[] )
  OR last_modifier=21321
LIMIT 5000;

El análisis de explicar ahora es:

 Limit  (cost=92.58..9442.38 rows=2478 width=8) (actual time=0.071..0.074 rows=1 loops=1)
   InitPlan 2 (returns $1)
     ->  Result  (cost=0.01..0.02 rows=1 width=0) (actual time=0.010..0.011 rows=1 loops=1)
           InitPlan 1 (returns $0)
             ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.001..0.002 rows=1 loops=1)
   ->  Bitmap Heap Scan on publication  (cost=92.56..9442.36 rows=2478 width=8) (actual time=0.069..0.070 rows=1 loops=1)
         Recheck Cond: ((mtid = ANY (($1)::bigint[])) OR (last_modifier = 21321))
         Heap Blocks: exact=1
         ->  BitmapOr  (cost=92.56..92.56 rows=2478 width=0) (actual time=0.060..0.060 rows=0 loops=1)
               ->  Bitmap Index Scan on publication_pkey  (cost=0.00..44.38 rows=10 width=0) (actual time=0.046..0.046 rows=1 loops=1)
                     Index Cond: (mtid = ANY (($1)::bigint[]))
               ->  Bitmap Index Scan on publication_last_modifier_btree  (cost=0.00..46.94 rows=2468 width=0) (actual time=0.011..0.011 rows=0 loops=1)
                     Index Cond: (last_modifier = 21321)
 Planning time: 0.704 ms
 Execution time: 0.153 ms

Parece que podemos crear un analizador simple que encuentre y reescriba todas las subselecciones de esta manera, y agregarlo a un gancho de hibernación para manipular la consulta nativa.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *