2011-12-19 12 views
7

Tengo una tabla de palabras con un índice en (idioma_id, estado). Estos son los resultados para EXPLICAR ANALIZAR:Índice no utilizado cuando se utiliza LIMIT en postgres

No hay límite

explain analyze SELECT "words".* FROM "words" WHERE (words.language_id = 27) AND (state IS NULL); 

Bitmap Heap Scan on words (cost=10800.38..134324.10 rows=441257 width=96) (actual time=233.257..416.026 rows=540556 loops=1) 
Recheck Cond: ((language_id = 27) AND (state IS NULL)) 
-> Bitmap Index Scan on ls (cost=0.00..10690.07 rows=441257 width=0) (actual time=230.849..230.849 rows=540556 loops=1) 
Index Cond: ((language_id = 27) AND (state IS NULL)) 
Total runtime: 460.277 ms 
(5 rows) 

límite de 100

explain analyze SELECT "words".* FROM "words" WHERE (words.language_id = 27) AND (state IS NULL) LIMIT 100; 

Limit (cost=0.00..51.66 rows=100 width=96) (actual time=0.081..0.184 rows=100 loops=1) 
-> Seq Scan on words (cost=0.00..227935.59 rows=441257 width=96) (actual time=0.080..0.160 rows=100 loops=1) 
Filter: ((state IS NULL) AND (language_id = 27)) 
Total runtime: 0.240 ms 
(4 rows) 

Por qué sucede esto? ¿Cómo puedo hacer que el índice se use en todos los casos?

Gracias.

+4

LÍMITE sin un ORDER BY parecería ser de limitado (sin doble sentido) de valor. ¿Qué 100 filas espera devolver? –

+0

BTW: ¿cuál es la selectividad de language_id = 17 AND status IS NULL cláusula? ¿Cuál es el tamaño total de la tabla de palabras? – wildplasser

+0

cierto ... el pedido ocurre en id DESC. ¿Podría eso estar ralentizándolo? ¿Se necesita un índice en esa columna? @wildplasser el tamaño total es de 10 millones de filas, la selectividad es de aproximadamente 500,000 filas – alste

Respuesta

7

Creo que el planificador de consultas PostreSQL solo piensa que en el segundo caso, el que tiene el LIMIT, no vale la pena aplicar el índice, ya que [el LIMIT] es demasiado pequeño. Entonces no es un problema.

+0

Tienes razón, pero ¿cómo puedo evitar esto? En realidad, estoy usando el índice gins de jsonb y, debido al límite 1, este índice no se está utilizando y se está tomando mucho tiempo. – Anurag

0

También es extraño que las dos consultas devuelvan un número diferente de filas. Supongo que has estado insertando ... Uhm, ¿y si haces una sub selección?

select * from (select ...) limit 100; 
+1

"(5 filas)" se refiere a la cantidad de líneas en el plan de explicación, no a cuántas filas devuelve la consulta – Anna

3

Sin límite: rows = 540556 bucles = 1 Tiempo de ejecución total: 460.277 ms

Con límite: rows = 100 bucles = 1 Tiempo de ejecución total: 0.240 ms

no veo un problema aquí. Si su consulta arroja 500K filas, necesitará más tiempo.

3

Eche un vistazo a la documentación de PostgreSQL sobre Using EXPLAIN y Query Planning. El motivo por el que el planificador de consultas prefiere un escaneo secuencial sobre un escaneo de índice en el caso LIMIT 100 es simplemente porque el escaneo secuencial es más económico.

No hay una cláusula ORDER BY en la consulta, por lo que el planificador está bien con las primeras 100 filas (aleatorias) que coinciden con la condición del filtro. Un escaneo de índice requeriría leer primero las páginas de índice y luego leer las páginas de datos para buscar las filas correspondientes. El escaneo secuencial solo necesita leer las páginas de datos para buscar las filas. En su tabla de casos las estadísticas parecen sugerir que hay suficientes filas (aleatorias) que coinciden con la condición del filtro. El costo de las lecturas secuenciales de la página para obtener las 100 filas se considera más barato que el costo de leer el índice primero y luego buscar las filas reales. Es posible que vea un plan diferente cuando aumenta el límite o cuando menos filas coinciden con la condición del filtro.

Con los ajustes por defecto el planificador tiene en cuenta el coste de una página al azar leer (random_page_cost) cuatro veces el costo de una página de lectura secuencial (seq_page_cost). Esta configuración se puede ajustar para ajustar los planes de consulta (por ejemplo, cuando toda la base de datos está en RAM, una lectura de página aleatoria no es más costosa que una lectura de página secuencial y debe preferirse un escaneo de índice). También puede probar diferentes planes de consulta mediante la activación/desactivación de ciertos tipos de exámenes, por ejemplo:

set enable_seqscan = [on | off] 
set enable_indexscan = [on | off] 

Si bien es posible activar/desactivar ciertos tipos de exploraciones de forma global esta debe ser utilizado ad hoc para depuración o solución de problemas por sesión.

También ejecute VACUUM ANALYZE words antes de probar los planes de consulta, de lo contrario, un vacío automático (autovaccum) entre las pruebas podría influir en los resultados.

Cuestiones relacionadas