A contagem de linhas em tabelas grandes é conhecida por ser lenta no PostgreSQL. Para obter um número preciso, é necessário fazer uma contagem completa de linhas devido à natureza do MVCC . Há uma maneira de acelerar isso drasticamente se a contagem não precisar ser exata como parece ser no seu caso.
Em vez de obter a contagem exata ( lento com tabelas grandes):
SELECT count(*) AS exact_count FROM myschema.mytable;
Você obtém uma estimativa aproximada como esta ( extremamente rápido ):
SELECT reltuples::bigint AS estimate FROM pg_class where relname='mytable';
A proximidade da estimativa depende de você correr o ANALYZE
suficiente. Geralmente é muito próximo.
Veja o FAQ do PostgreSQL Wiki .
Ou a página wiki dedicada para contagem (*) de desempenho .
Melhor ainda
O artigo do PostgreSQL Wiki é foi um pouco desleixado . Ele ignorou a possibilidade de haver várias tabelas com o mesmo nome em um banco de dados - em esquemas diferentes. Para explicar isso:
SELECT c.reltuples::bigint AS estimate
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = 'mytable'
AND n.nspname = 'myschema'
Ou melhor ainda
SELECT reltuples::bigint AS estimate
FROM pg_class
WHERE oid = 'myschema.mytable'::regclass;
Mais rápido, simples, seguro e elegante. Veja o manual sobre Tipos de Identificadores de Objetos .
Use to_regclass('myschema.mytable')
no Postgres 9.4+ para evitar exceções para nomes de tabela inválidos:
SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);
Como @a_horse comentou , a cláusula recém-adicionada para o SELECT
comando pode ser útil se as estatísticas em pg_class
não forem atualizadas o suficiente por algum motivo. Por exemplo:
- Sem
autovacuum
correr.
- Imediatamente após um grande
INSERT
ou DELETE
.
TEMPORARY
tabelas (que não são cobertas por autovacuum
).
Isso só olha para uma seleção aleatória de n % ( 1
no exemplo) de blocos e conta as linhas nela. Uma amostra maior aumenta o custo e reduz o erro, sua escolha. A precisão depende de mais fatores:
- Distribuição do tamanho da linha. Se um determinado bloco tiver linhas mais largas do que o normal, a contagem será menor do que o normal, etc.
- Tuplas mortas ou um
FILLFACTOR
espaço de ocupação por bloco. Se distribuída de forma desigual pela tabela, a estimativa pode estar errada.
- Erros gerais de arredondamento.
Na maioria dos casos, a estimativa de pg_class
será mais rápida e precisa.
Resposta à pergunta real
Primeiro, preciso saber o número de linhas dessa tabela, se a contagem total for maior do que alguma constante predefinida,
E se isso ...
... é possível no momento em que a contagem passar do meu valor constante, ele irá parar a contagem (e não esperar terminar a contagem para informar que a contagem de linhas é maior).
Sim. Você pode usar uma subconsulta comLIMIT
:
SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;
Na verdade, o Postgres para de contar além do limite fornecido, você obtém uma contagem exata e atual de até n linhas (500.000 no exemplo) e n caso contrário. Não tão rápido quanto a estimativa pg_class
, no entanto.