¿Por qué PostgreSQL realiza una exploración secuencial en una columna indexada?

151

Ejemplo muy simple: una tabla, un índice, una consulta:

CREATE TABLE book
(
  id bigserial NOT NULL,
  "year" integer,
  -- other columns...
);

CREATE INDEX book_year_idx ON book (year)

EXPLAIN
 SELECT *
   FROM book b
  WHERE b.year > 2009

me da

Seq Scan on book b  (cost=0.00..25663.80 rows=105425 width=622)
  Filter: (year > 2009)

¿Por qué NO realiza exploración de índice en su lugar? ¿Qué me estoy perdiendo?

Alex Vayda
fuente

Respuestas:

223

Si SELECT devuelve más de aproximadamente el 5-10% de todas las filas de la tabla, una exploración secuencial es mucho más rápida que una exploración de índice.

Esto se debe a que una exploración de índice requiere varias operaciones de E / S para cada fila (busque la fila en el índice, luego recupere la fila del montón). Mientras que una exploración secuencial solo requiere un único IO para cada fila, o incluso menos porque un bloque (página) en el disco contiene más de una fila, por lo que se puede recuperar más de una fila con una sola operación de IO.

Por cierto: esto también es cierto para otros DBMS: algunas optimizaciones como "escaneos de solo índice" se dejan de lado (pero para un SELECT * es muy poco probable que un DBMS realice un "escaneo de solo índice")

un caballo sin nombre
fuente
12
El 5-10% depende de un par de ajustes de configuración y el almacenamiento de los datos también. No es un número difícil.
Frank Heikens
66
@Frank: por eso dije "aproximadamente" :) Pero gracias por señalarlo
a_horse_with_no_name
55
Además, un escaneo secuencial puede solicitar varias páginas del montón a la vez, y pedirle al núcleo que recupere el siguiente fragmento mientras funciona en el actual: un escaneo de índice recupera una página a la vez. (Un escaneo de mapa de bits hace un compromiso entre los dos, generalmente se ve que aparece en un plan para consultas que no son lo suficientemente selectivas para un escaneo de índice, pero que no son tan poco selectivas como para merecer un escaneo de tabla completo)
araqnid
44
La pregunta interesante es ¿cómo sabe la base de datos cuántas filas devolverá la consulta sin hacerlo primero? ¿Almacena estadísticas como el número de valores diferentes frente al tamaño de la tabla en alguna parte?
Laurent Grégoire
77
@ LaurentGrégoire: sí, la base de datos almacena estadísticas sobre el número de filas y la distribución de valores. Consulte el manual para obtener más detalles: postgresql.org/docs/current/static/planner-stats.html
a_horse_with_no_name
13

¿ ANALIZASTE la tabla / base de datos? ¿Y qué hay de las estadísticas ? Cuando hay muchos registros en el año> 2009, una exploración secuencial puede ser más rápida que una exploración de índice.

Frank Heikens
fuente
0

En el escaneo de índice, lea los saltos de cabeza de una fila a otra, que es 1000 veces más lento que leer el siguiente bloque físico (en el escaneo secuencial).

Por lo tanto, si el (número de registros a recuperar * 1000) es menor que el número total de registros, la exploración del índice funcionará mejor.

Gaurav Neema
fuente
0

@a_horse_with_no_name lo explicó bastante bien. Además, si realmente desea usar un escaneo de índice, generalmente debe usar rangos acotados en la cláusula where. por ejemplo, año> 2019 y año <2020.

Muchas veces las estadísticas no se actualizan en una tabla y es posible que no sea posible debido a restricciones. En este caso, el optimizador no sabrá cuántas filas debe tomar en el año> 2019. Por lo tanto, selecciona una exploración secuencial en lugar de un conocimiento completo. Las particiones limitadas resolverán el problema la mayor parte del tiempo.

Shitij Goyal
fuente