¿Puede PostgreSQL usar nulos en sus índices?

10

He estado leyendo este libro que dice que

La base de datos supone que Indexed_Col IS NOT NULL cubre un rango demasiado grande para ser útil, por lo que la base de datos no se dirigirá a un índice desde esta condición.

Reconozco que el libro tiene más de 10 años, pero ya ha demostrado ser bastante útil: utilizando las instrucciones extraídas de sus páginas, he acelerado una consulta por un factor de diez.

Además, al ejecutar EXPLAIN ANALYZEuna SELECTconsulta, descubrí que ninguno de mis índices se está utilizando, incluso cuando todos los derechos deberían serlo.

Por lo tanto, mi pregunta es:

Supongamos que hay una tabla que tiene una columna, cuya definición de columna incluye "NOT NULL", y que existe un índice que cubre esta columna, ¿se usaría este índice en una consulta de esa tabla donde las columnas son parte de la consulta?

Me gusta:

CREATE TABLE my_table(
a varchar NOT NULL
);

CREATE INDEX ix_my_table ON my_table(a);

SELECT a from my_table;
FuriousFolder
fuente

Respuestas:

9

PostgreSQL ciertamente puede usar un índice para IS NOT NULL. Tampoco veo ninguna suposición del planificador de consultas sobre esa condición.

Si la fracción nula para la columna ( pg_statistic.stanullfrac) es lo suficientemente baja como para sugerir que el índice es útil para la consulta, PostgreSQL usará un índice.

No puedo entender lo que estás tratando de decir con:

Si esto es correcto, ¿entiendo que un índice en una columna definida como "NO NULO" no se utilizará en una consulta que use esa columna?

Ciertamente, un índice no se utilizará para una IS NOT NULLcondición en una NOT NULLcolumna. Siempre coincidirá con el 100% de las filas, por lo que un seqscan casi siempre será mucho más rápido.

PostgreSQL no usará un índice si el índice no filtra una gran proporción de filas para una consulta. La única excepción probable es cuando solicita un conjunto de columnas cubiertas por un único índice, en un orden que coincida con el del índice. PostgreSQL podría hacer un escaneo de solo índice entonces. Por ejemplo, si hay un índice t(a, b, c)y usted:

select a, b FROM t ORDER BY a, b, c;

PostgreSQL podría usar su índice, aunque no se filtren filas, ya que solo tiene que leer el índice y puede omitir la lectura del montón, evitar hacer una clasificación, etc.

Craig Ringer
fuente
Todo esto es cierto a partir de PG 9.0
eradman
1
E incluso en una columna anulable, una consulta con condición WHERE column IS NOT NULLpuede no usar el índice porque, como dice el libro: "cubre un rango demasiado grande para ser útil". Si el 90% de los valores no son nulos, un seqscan probablemente también sea más rápido.
ypercubeᵀᴹ
Exactamente. Podría, pero solo si una gran fracción de la tabla es nula. A menudo, en este caso, un índice parcial es una mejor opción de todos modos.
Craig Ringer
Si. Estaba tratando de decir que (según tengo entendido) la parte "cubre un rango demasiado grande" se refiere al índice, pero en lo que respecta a la condición específica y no al índice en general.
ypercubeᵀᴹ
2
@FuriousFolder Heh, hay demasiadas negaciones aquí. PostgreSQL no usará un índice en una NOT NULLcolumna para una IS NOT NULLconsulta a menos que ese índice también sea útil para otras partes de la WHEREcláusula, filtros de unión, etc., o sea utilizable para una exploración ordenada de solo índice. En otras palabras, ignorará por completo el redundante IS NOT NULLen la NOT NULLcolumna y hará que las opciones de uso del índice se basen en otros detalles. (Consulte editar, volver a escanear solo índices).
Craig Ringer
2

Además de la respuesta exhaustiva de Craig, quería agregar que la portada del libro al que hace referencia dice:

Cubre Oracle, DB2 y SQL Server

Por lo tanto, no confiaría en que sea una gran fuente de asesoramiento sobre PostgreSQL en particular. ¡Cada RDBMS puede ser sorprendentemente diferente!

Estoy un poco confundido acerca de su pregunta original, pero aquí hay un ejemplo que muestra que la sección del libro no es 100% correcta. Para evitar más confusión, aquí está todo el párrafo relevante, puede verlo en Google Book Search .

La base de datos supone que Indexed_Col IS NOT NULL cubre un rango demasiado grande para ser útil, por lo que la base de datos no se dirigirá a un índice desde esta condición. En casos raros, tener un valor no nulo es tan raro que resulta beneficioso un escaneo de rango de índice sobre todos los valores no nulos posibles. En tales casos, si puede encontrar un límite inferior o superior seguro para el rango de todos los valores posibles, puede habilitar un escaneo de rango con una condición como Positivo_Columna_ID> -1 o Fecha_Columna> TO_DATE ('0001/01/01' , 'AAAA / MM / DD').

Postgres puede en realidad (en el siguiente caso artificial) usar un índice para satisfacer IS NOT NULLconsultas sin agregar kludges de escaneo de rango como el sugerido Positive_ID_Column > -1. Vea los comentarios sobre las preguntas de Craig sobre por qué Postgres está eligiendo este índice en este caso particular, y la nota sobre el uso de índices parciales.

CREATE TABLE bar (a int);
INSERT INTO bar (a) SELECT NULL FROM generate_series(1,1000000);
INSERT INTO bar (a) VALUES (1);
CREATE INDEX bar_idx ON bar (a);

EXPLAIN ANALYZE SELECT * FROM bar WHERE a IS NOT NULL;
                                                QUERY PLAN                                                    
------------------------------------------------------------------------------------------------------------------
 Index Only Scan using bar_idx on bar  (cost=0.42..8.44 rows=1 width=4) (actual time=0.094..0.095 rows=1 loops=1)
   Index Cond: (a IS NOT NULL)
   Heap Fetches: 1
 Total runtime: 0.126 ms
(4 rows)

Por cierto, esto es Postgres 9.3, pero creo que los resultados serían más o menos similares en 9.1, aunque no usaría un "Escaneo de solo índice".

Editar: veo que ha aclarado su pregunta original, y aparentemente se pregunta por qué Postgres no está usando un índice en un ejemplo simple como:

CREATE TABLE my_table(
a varchar NOT NULL
);

CREATE INDEX ix_my_table ON my_table(a);

SELECT a from my_table;

Probablemente porque no tienes filas en la tabla. Entonces agregue algunos datos de prueba y ANALYZE my_table;.

Josh Kupershmidt
fuente
En la descripción de dicho libro (énfasis mío): "El autor Dan Tow describe un método de ahorro de tiempo que ha desarrollado para encontrar el plan de ejecución óptimo, rápida y sistemáticamente, independientemente de la complejidad del SQL o la plataforma de base de datos que se esté utilizando ". quizás pasó por alto el n. ° 1 de la pregunta, a saber, que la columna se define como NOT NULL, no que la consulta utiliza IS NOT NULLcomo condición de índice. Esto está en los comentarios a los que hizo referencia, pero actualizaré la pregunta para incluirla.
FuriousFolder
Además, el libro en sí es independiente del lenguaje: las únicas partes específicas de DMBS son sobre mostrar planes de consulta, lo que Postgres simplifica bastante :)
FuriousFolder
1
@FuriousFolder la columna se define como NOT NULL pero esta parte (en su pregunta, del libro): "that Indexed_Col IS NOT NULL cubre ..." se refiere a la condición where y no a la definición de la columna. Aunque es difícil estar seguro, porque está fuera de contexto. Quizás deberías incluir el párrafo completo (anterior) del libro.
ypercubeᵀᴹ
-1

No ha publicado su consulta o datos de ejemplo. Pero la razón más común por la que no se usan los índices tiene que ver con el volumen.

Los índices son como una agenda telefónica que traduce una columna a una ubicación de fila. Si solo está buscando unas pocas filas, tiene sentido buscar cada fila en la agenda y luego buscar la fila en la tabla principal.

Pero durante más de unas pocas filas, es más barato omitir la agenda e iterar sobre todas las filas de la tabla principal. En mi experiencia, el punto de inflexión es de alrededor de 100 filas.

Andomar
fuente
"Los índices son como una agenda telefónica que traduce una columna a una ubicación de fila. Si solo está buscando unas pocas filas, tiene sentido buscar cada fila en la agenda telefónica y luego buscar la fila en la tabla principal". En realidad, los índices son como directorios telefónicos más pequeños que se actualizan cada vez que se actualiza el directorio telefónico que indexan. Usted sabe que cada vez que abra una agenda telefónica más pequeña, encontrará toda la información que describe su condición de indexación. Por ejemplo, todas las personas llamadas 'Frank' en una tabla de índices: CREATE INDEX ix_frank ON people(name) WHERE name ='frank'.
FuriousFolder
Esto permite que un escaneo de solo índice sea mucho más rápido, ya que puede leer toda la "agenda telefónica más pequeña" en la memoria, lo que no es factible con una tabla alineada multimillonaria.
FuriousFolder
@FuriousFolder: está describiendo una exploración de solo índice. Pero el OP dice que sus índices no se están utilizando, lo que no sucedería si un escaneo de solo índice satisfaría la consulta.
Andomar
Andomar ... Soy el OP, jaja. Mi objetivo es exactamente eso; para obtener esta consulta para usar un escaneo de solo índice. Desde entonces lo he logrado, ya que Craig explicó que Postgres es capaz de usar un índice en una columna donde la definición de la columna incluye NOT NULL
FuriousFolder