Postgres: contagem (*) vs contagem (id)

11

Vi na documentação a diferença entre count(*)e count(pk). Eu estava usando count(pk)(onde pkestá a SERIAL PRIMARY KEY) não saber sobre a existência de count(*).

Minha pergunta é sobre as otimizações internas do Postgres. É inteligente o suficiente perceber que SERIAL PRIMARY KEYa existirá em todas as linhas e nunca será falso e apenas contará linhas ou fará verificações de predicado redundantes para cada linha? Concordo que isso provavelmente é uma otimização sem sentido, mas estou curioso.

Dei uma olhada na saída de EXPLAINe EXPLAIN VERBOSEpara count(*), count(id)e count(id > 50)para ver se EXPLAINmencionou a verificação dos predicados em sua saída. Não faz.

ldrg
fonte

Respostas:

15

Eu obtive resultados consistentes em meus testes repetidos com várias versões nos últimos anos:
count(*)é um pouco mais rápido que count(pk). Também é mais curto e na maioria das vezes se encaixa melhor no que é testado: a existência de uma linha.

Relativo:

O Postgres é inteligente o suficiente para entender que SERIAL PRIMARY KEYa existirá em todas as linhas e nunca será falso

A única coisa relevante é a NOT NULLrestrição. O PRIMARY KEYé NOT NULLautomaticamente serialou never falseé ortogonal à pergunta.

Com count(col), se o PostgreSQL estivesse tentando ser inteligente e verificar o catálogo do sistema se uma coluna era NOT NULLe retornar a um equivalente count(*), você ainda teria mais uma pesquisa em uma tabela do sistema do que com count(*).

Quanto à EXPLAINsaída, não é uma dica:

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) ...

Significado, nãocount(col) é convertido em , mesmo que esteja definido .count(*)NOT NULL

Erwin Brandstetter
fonte
Este ainda é o caso das novas versões? Eu acho que realmente não precisaria de uma pesquisa para cada consulta - poderia ser armazenada em cache.
Ondra Žižka
1
Aliás, com uma NOT NULLcoluna, a diferença é grande se você tiver muitas linhas. No nosso caso, com milhões de linhas, COUNT(*)é 3 vezes mais rápido. (Postgres 9.4)
Ondra raižka