Postgres: cuenta (*) vs cuenta (id)

11

Vi en la documentación la diferencia entre count(*)y count(pk). Había estado usando count(pk)(donde pkestá a SERIAL PRIMARY KEY) sin saber sobre la existencia de count(*).

Mi pregunta es sobre las optimizaciones internas de Postgres. ¿Es lo suficientemente inteligente como para darse cuenta de que SERIAL PRIMARY KEYa existirá en cada fila y nunca será falso y solo contará filas o hará verificaciones redundantes de predicados para cada fila? Estoy de acuerdo en que esta es probablemente una optimización demasiado inútil, pero tengo curiosidad.

Eché un vistazo a la salida de EXPLAINy EXPLAIN VERBOSEpara count(*), count(id)y count(id > 50)para ver si EXPLAINmencionó verificar los predicados en su salida. No lo hace.

ldrg
fuente

Respuestas:

15

Obtuve resultados consistentes en mis repetidas pruebas con varias versiones en los últimos años:
count(*)es un poco más rápido que count(pk). También es más corto y la mayoría de las veces se ajusta mejor a lo que se prueba: la existencia de una fila.

Sobre:

¿Es Postgres lo suficientemente inteligente como para darse cuenta de que SERIAL PRIMARY KEYa existirá en cada fila y nunca será falso?

Lo único relevante es la NOT NULLrestricción. El PRIMARY KEYes NOT NULLautomáticamente, serialo never falseson ortogonales a la pregunta.

Con count(col), si PostgreSQL intentaba ser inteligente y comprobar el catálogo del sistema si era una columna NOT NULLy recurrir a un equivalente count(*), aún tendría una búsqueda más en una tabla del sistema que con count(*).

En cuanto a EXPLAINla producción, no es una pista:

EXPLAIN SELECT count(*) FROM ...

Aggregate  (cost=4963.38..4963.43 rows=1 width=0) ...


EXPLAIN SELECT count(pk) FROM ...

Aggregate  (cost=4963.38..4963.43 rows=1 width=4) ...

Es decir, count(col)se no se convierte en count(*), incluso si está definido NOT NULL.

Erwin Brandstetter
fuente
¿Sigue siendo el caso con las nuevas versiones? Creo que realmente no necesitaría una búsqueda para cada consulta, podría almacenarse en caché.
Ondra Žižka
1
Por cierto, con una NOT NULLcolumna, la diferencia es grande si tienes muchas filas. En nuestro caso con millones de filas, COUNT(*)es 3 veces más rápido. (Postgres 9.4)
Ondra Žižka