Por que a contagem (*) é lenta, quando o explica sabe a resposta?

14

Esta consulta: select count(*) from planner_eventleva muito tempo para ser executada - por muito tempo, desisti e a matei antes que ela terminasse. No entanto, quando executo explain select count(*) from planner_event, vejo uma coluna na saída com o número de linhas (14m).

Como a explicação pode obter o número de linhas instantaneamente, mas a contagem (*) leva muito tempo para ser executada?

Benubird
fonte
COUNT (*) sem uma causa WHERE causará uma varredura de tabela no mecanismo InnoDB. O MyISAM pode entregar a contagem diretamente porque a COUNT é mantida no arquivo de cabeçalho fora da tabela.
Raymond Nijland

Respostas:

16

O Explain está usando estatísticas reunidas anteriormente (usadas pelo otimizador de consulta). Fazendo um select count(*)lê TODOS os blocos de dados.

Aqui está uma maneira barata de obter uma contagem estimada de linhas:

select TABLE_ROWS FROM INFORMATION_SCHEMA.TABLES where TABLE_NAME='planner_event';

Mesmo se você tiver select count(id), ainda poderá demorar muito tempo, a menos que você tenha um índice secundário id(também assumindo que idé uma CHAVE PRIMÁRIA). Como todos os dados (incluindo Dados da linha) são armazenados nos índices da Árvore B, a execução de select count(PK_COLUMN)ainda é uma quantidade considerável de E / S (é necessário ler todas as páginas de dados). Se você tiver um índice secundário no campo PK, ele poderá executar menos E / S para realizar uma contagem.

Kevin Bott
fonte
I_S.TABLES fornece a mesma estimativa que EXPLAINfornece.
Rick James
A consulta está ausente AND TABLE_SCHEMA='my_database' , caso contrário, você obterá vários resultados novamente se tiver uma tabela com o mesmo nome em outro banco de dados.
cz
3

O Explain obtém o número de algumas "estatísticas" usadas para estimar itens para o Otimizador. Esse número pode estar longe de estar correto - às vezes vejo que é mais do que um fator de 2 (maior ou menor) que o valor exato.

A execução COUNT(*)de uma tabela no InnoDB deve varrer a tabela para evitar a contagem incorreta de registros que estão ocupados sendo inseridos / excluídos por outras conexões, mas ainda não "confirmados". Na verdade, é bom o suficiente fazer uma varredura completa em algum índice, não necessariamente na tabela inteira (que contém o PRIMARY KEY).

Quanta RAM você tem? Qual é o valor de innodb_buffer_pool_size? Pode ajudar se isso for cerca de 70% da RAM.

Rick James
fonte