PEDIDO lento con LIMIT


11

Tengo esta consulta:

SELECT * 
FROM location 
WHERE to_tsvector('simple',unaccent2("city"))
   @@ to_tsquery('simple',unaccent2('wroclaw')) 
order by displaycount

Estoy feliz con eso:

"Sort  (cost=3842.56..3847.12 rows=1826 width=123) (actual time=1.915..2.084 rows=1307 loops=1)"
"  Sort Key: displaycount"
"  Sort Method: quicksort  Memory: 206kB"
"  ->  Bitmap Heap Scan on location  (cost=34.40..3743.64 rows=1826 width=123) (actual time=0.788..1.208 rows=1307 loops=1)"
"        Recheck Cond: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"        ->  Bitmap Index Scan on location_lower_idx  (cost=0.00..33.95 rows=1826 width=0) (actual time=0.760..0.760 rows=1307 loops=1)"
"              Index Cond: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"Total runtime: 2.412 ms"

Pero cuando agrego LIMIT, la ejecución tarda más de 2 segundos:

SELECT * 
FROM location 
WHERE to_tsvector('simple',unaccent2("city"))
   @@ to_tsquery('simple',unaccent2('wroclaw')) 
order by displaycount 
limit 20

Explique:

"Limit  (cost=0.00..1167.59 rows=20 width=123) (actual time=2775.452..2775.643 rows=20 loops=1)"
"  ->  Index Scan using location_displaycount_index on location  (cost=0.00..106601.25 rows=1826 width=123) (actual time=2775.448..2775.637 rows=20 loops=1)"
"        Filter: (to_tsvector('simple'::regconfig, unaccent2((city)::text)) @@ '''wroclaw'''::tsquery)"
"Total runtime: 2775.693 ms"

Creo que es un problema con ORDER BY y LIMIT. ¿Cómo puedo forzar a PostgreSQL a usar el índice y hacer el pedido al final?

Subconsulta no ayuda:

SELECT * 
FROM (
    SELECT * 
    FROM location 
    WHERE to_tsvector('simple',unaccent2("city"))
       @@ to_tsquery('simple',unaccent2('wroclaw')) 
    order by displaycount
) t 
LIMIT 20;

o:

SELECT * 
FROM (
    SELECT * 
    FROM location 
    WHERE to_tsvector('simple',unaccent2("city"))
       @@ to_tsquery('simple',unaccent2('wroclaw'))
) t 
order by displaycount 
LIMIT 20;

Respuestas:


12

Supongo que esto solucionaría su consulta:

SELECT * 
FROM   location 
WHERE     to_tsvector('simple',unaccent2(city))
       @@ to_tsquery('simple',unaccent2('wroclaw')) 
ORDER  BY to_tsvector('simple',unaccent2(city))
       @@ to_tsquery('simple',unaccent2('wroclaw')) DESC
         ,displaycount 
LIMIT  20;

Repito la WHEREcondición como primer elemento de la ORDER BYcláusula, que es lógicamente redundante, pero debería evitar que el planificador de consultas suponga que sería mejor procesar filas según el índice location_displaycount_index, lo que resulta ser mucho más costoso.

El problema subyacente es que el planificador de consultas obviamente juzga erróneamente la selectividad y / o el costo de su WHEREcondición. Solo puedo especular por qué es así.

¿Tiene autovacuum en ejecución, que también debería ocuparse de ejecutar ANALYZEen sus mesas? Por lo tanto, ¿están actualizadas sus estadísticas de tabla? Cualquier efecto si corres:

ANALYZE location;

¿E intenta de nuevo?

También puede ser que la selectividad del @@operador esté siendo mal juzgada. Me imagino que es muy difícil de estimar por razones lógicas.


Si mi consulta no resuelve el problema, y ​​en general para verificar la teoría subyacente, haga una de estas dos cosas:

Este último es menos intrusivo y solo afecta la sesión actual. Se deja a los métodos bitmap heap scany bitmap index scanabierta, que son utilizados por el plan más rápido.
Luego, vuelva a ejecutar la consulta.

Por cierto: si la teoría es sólida, su consulta (como la tiene ahora) será mucho más rápida con un término de búsqueda menos selectivo en la condición FTS, al contrario de lo que podría esperar. Intentalo.


1
La consulta funciona. Desactivar el indexscan también funciona. ANALIZAR no funciona. Muchas gracias por la respuesta integral.
ziri

0

Cuando se utiliza un ajuste LIMIT postgresql, su plan es óptimo para recuperar solo el subconjunto de fila. Desafortunadamente, de alguna manera toma una decisión equivocada en su caso. Esto podría deberse a que las estadísticas de la tabla son demasiado antiguas. Intente actualizar la estadística emitiendo VACUUM ANALYZE location;

Forzar el uso de índices normalmente se realiza deshabilitando el uso de exploraciones secuenciales (establezca enable_seqscan = false). Sin embargo, en su caso, no está haciendo una exploración secuencial, simplemente cambia a un índice diferente para la consulta con el LÍMITE.

En caso de que el análisis no ayude, ¿podría decir qué versión de postgresql está utilizando? Además, ¿cuántas filas hay en la tabla?


Analizar no ayudó. La tabla tiene aproximadamente 36000 filas y estoy usando postgresql 9.1.
ziri
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.