Pergunta

Eu sei que é geralmente uma má idéia fazer consultas como esta:

SELECT * FROM `group_relations`

Mas quando eu só quero a contagem, eu deveria ir para esta consulta, uma vez que permite que a tabela para a mudança, mas ainda produz os mesmos resultados.

SELECT COUNT(*) FROM `group_relations`

Ou o mais specfic

SELECT COUNT(`group_id`) FROM `group_relations`

Eu tenho um lá sentindo o último poderia ser mais rápido, mas existem outras coisas a considerar?

Atualizar :. Eu estou usando InnoDB, neste caso, desculpe por não ser mais específica

Foi útil?

Solução

Se a coluna em questão não é NULL, ambas as consultas são equivalentes. Quando group_id contém valores nulos,

select count(*)

contará todas as linhas, enquanto

select count(group_id)

só vai contar as linhas onde group_id não é nulo.

Além disso, alguns sistemas de banco de dados, como MySQL empregar uma otimização quando você perguntar para count (*), que faz tais perguntas um pouco mais rápido do que o específico.

Pessoalmente, quando apenas contando, estou fazendo count (*) para estar no lado seguro com os valores nulos.

Outras dicas

Se eu me lembro bem, em COUNT MYSQL (*) conta todas as linhas, enquanto que COUNT (column_name) conta apenas as linhas que têm um valor não-NULL na coluna dada.

COUNT (*) conta todas as linhas, enquanto COUNT (column_name) contará apenas as linhas sem valores nulos na coluna especificada.

importante notar no MySQL:

COUNT () é muito rápido em tabelas MyISAM para colunas * ou não-nulo, uma vez que a contagem de linha é armazenada em cache. InnoDB não tem contagem de cache fila, então não há nenhuma diferença no desempenho para COUNT (*) ou COUNT (column_name), independentemente se a coluna pode ser nulo ou não. Você pode ler mais sobre as diferenças em este post no MySQL blogue desempenho.

Se você tentar SELECT COUNT(1) FROMgroup_relations ele vai ser um pouco mais rápido porque ele não vai tentar recuperar informações de suas colunas.

Edit: Eu apenas fiz alguma pesquisa e descobri que isso só acontece em alguns db. Em sqlserver é a mesma de usar 1 ou *, mas no Oracle é mais rápido para usar 1.

http: //social.msdn.microsoft.com/forums/en-US/transactsql/thread/9367c580-087a-4fc1-bf88-91a51a4ee018/

Aparentemente, não há diferença entre eles no mysql, como sqlserver o analisador parece alterar a consulta para selecionar (1). Desculpe se eu enganá-lo de alguma forma.

Eu estava curioso sobre isso mesmo. É tudo muito bem para ler documentação e teóricas respostas, mas eu gosto de equilibrar aqueles com evidência empírica.

Eu tenho uma tabela MySQL (InnoDB), que tem 5,607,997 fichas nele. A tabela é na minha própria caixa de areia privada, então eu sei o conteúdo é estático e ninguém mais está usando o servidor. Eu acho que isso efetivamente remove todos fora afeta no desempenho. Eu tenho uma tabela com um auto_increment campo de chave primária (Id) que eu conheço nunca será nula de que vou usar para o meu, onde test cláusula (ONDE ID não é NULL).

A única outra falha possível que eu vejo em testes de corrida é o cache. A primeira vez que uma consulta é executada será sempre mais lento do que consultas subsequentes que usam os mesmos índices. Vou referir a esse abaixo como a chamada de cache Sementeira. Só para misturar-se um pouco que ele correu com uma cláusula onde eu sei que vai avaliar sempre a verdade, independentemente de quaisquer dados (TRUE = TRUE).

Dito isto, aqui estão meus resultados:

QueryType

      |  w/o WHERE          | where id is not null |  where true=true

COUNT ()

      |  9 min 30.13 sec ++ | 6 min 16.68 sec ++   | 2 min 21.80 sec ++
      |  6 min 13.34 sec    | 1 min 36.02 sec      | 2 min 0.11 sec 
      |  6 min 10.06 se     | 1 min 33.47 sec      | 1 min 50.54 sec

COUNT (Id)

      |  5 min 59.87 sec    | 1 min 34.47 sec      | 2 min 3.96 sec 
      |  5 min 44.95 sec    | 1 min 13.09 sec      | 2 min 6.48 sec

COUNT (1)

      | 6 min 49.64 sec    | 2 min 0.80 sec       | 2 min 11.64 sec
      | 6 min 31.64 sec    | 1 min 41.19 sec      | 1 min 43.51 sec

++ Esta é considerada a chamada Semeando cache. Espera-se a ser mais lento do que o resto.

Eu diria que os resultados falam por si. COUNT (Id) geralmente bordas para fora os outros. Adicionando uma cláusula Where diminui drasticamente o tempo de acesso mesmo que seja uma cláusula você sabe que vai avaliar a verdade. O ponto doce parece ser COUNT (Id) ... WHERE ID não é NULL.

Eu adoraria ver os resultados de outras pessoas, talvez com tabelas menores ou com o local onde cláusulas contra diferentes campos do que o campo que você está contando. Estou certo de que há outras variações eu não ter tido em conta.

buscar alternativas

Como você viu, quando as tabelas crescer grande, consultas COUNT ficar lento. Eu acho que a coisa mais importante é considerar a natureza do problema que você está tentando resolver. Por exemplo, muitos desenvolvedores usar consultas COUNT ao gerar a paginação para grandes conjuntos de registros, a fim de determinar o número total de páginas no conjunto de resultados.

Sabendo que as consultas COUNT vai crescer lento, você poderia considerar uma forma alternativa de controles de exibição de paginação que simplesmente permite que você side-passo a consulta lenta. pagination do Google é um excelente exemplo.

desnormalizar

Se você absolutamente deve saber o número de registros correspondentes a contagem específica, considere a técnica clássica de desnormalização dados. Em vez de contar o número de linhas em tempo de pesquisa, considere incrementar um contador na inserção de registro, e diminuindo esse contador de exclusão do registro.

Se você decidir fazer isso, considere o uso idempotentes, operações transacionais para manter esses valores desnormalizada em sincronia.

BEGIN TRANSACTION;
INSERT INTO  `group_relations` (`group_id`) VALUES (1);
UPDATE `group_relations_count` SET `count` = `count` + 1;
COMMIT;

Como alternativa, você poderia usar gatilhos de banco de dados se o seu RDBMS apoia-los.

Dependendo da sua arquitetura, pode fazer sentido usar uma camada de caching como memcached para armazenar, aumentar e diminuir o valor desnormalizada, e simplesmente cair para a consulta COUNT lento quando a chave de cache está faltando. Isso pode reduzir write-contenção no geral, se você tem dados muito voláteis, embora em casos como este, você vai querer considerar soluções para o cão-pilha efeito .

MySQL tabelas ISAM deve ter otimização para COUNT (*), pular varredura completa da tabela.

Um asterisco em CONTAGEM não tem qualquer influência com asterisco para a selecção de todos os campos da tabela. É puro lixo para dizer que COUNT (*) é mais lento do que COUNT (campo)

intuo que SELECT COUNT (*) é mais rápido que select count (campo). Se o RDBMS detectou que você especificar "*" na contagem em vez de campo, ele não precisa de avaliar nada a contagem de incremento. Enquanto que se você especificar campo na contagem, o RDBMS será sempre avaliar se o seu campo é nulo ou não contá-lo.

Mas se o seu campo é anulável, especifique o campo em COUNT.

COUNT (*) fatos e mitos:

MITO : "InnoDB não controla count (*) consulta bem":

A maioria COUNT (*) as consultas são executadas mesma forma por todos os mecanismos de armazenamento, se você tem uma cláusula WHERE, caso contrário você InnoDB terá que executar uma varredura completa da tabela.

FATO : InnoDB não otimiza count (*) consultas sem a cláusula onde

É melhor contar por uma coluna indexada como uma chave primária.

SELECT COUNT(`group_id`) FROM `group_relations`

Deve depender do que você está realmente tentando alcançar como Sebastian já disse, ou seja, fazer suas intenções claras! Se você são apenas contando as linhas, em seguida, ir para o COUNT (*), ou contagem de um único movimento da coluna para a COUNT (coluna).

Pode valer a pena conferir o fornecedor DB também. De volta quando eu costumava usar Informix teve uma otimização para COUNT (*), que teve um custo de consulta plano de execução de 1 em comparação com a contagem colunas simples ou mutliple o que resultaria em um valor mais elevado

Se você tentar SELECT COUNT (1) DE group_relations ele vai ser um pouco mais rápido porque ele não vai tentar recuperar informações de suas colunas.

COUNT (1) costumava ser mais rápido do que COUNT (*), mas isso não é mais verdade, já DBMS modernos são bastante inteligente para saber que você não quer saber sobre colunas

O conselho que recebi do MySQL sobre coisas como esta é que, em geral, tentando otimizar uma consulta com base em truques como esta pode ser uma maldição, a longo prazo. Há exemplos ao longo da história do MySQL onde a técnica de alto desempenho de alguém que depende de como o otimizador trabalha acaba sendo o gargalo no próximo lançamento.

Escrever a consulta que responde a pergunta que você está pedindo - se você quiser uma contagem de todas as linhas, o uso COUNT (*). Se você quer uma contagem de colunas não nulas, uso de COUNT (col) ONDE col IS NOT NULL. Índice de forma adequada, e deixar a otimização para o otimizador. Tentando fazer suas próprias otimizações de nível de consulta, por vezes, pode fazer o built-in otimizador menos eficaz.

Dito isto, há coisas que você pode fazer em uma consulta para tornar mais fácil para o otimizador para acelerá-lo, mas eu não acredito que COUNT é um deles.

Edit: As estatísticas na resposta acima são interessantes, no entanto. Eu não tenho certeza se existe realmente alguma coisa no trabalho no otimizador neste caso. Eu só estou falando sobre otimizações de nível de consulta em geral.

Eu sei que é geralmente uma má idéia fazer consultas como esta:

SELECT * FROM `group_relations`

Mas quando eu só quero a contagem, deve I ir para esta consulta, uma vez que permite a mesa para mudar, mas ainda produz os mesmos resultados.

SELECT COUNT(*) FROM `group_relations`

Como a pergunta indica, o SELECT * razão é mal aconselhado é que alterações na tabela poderia exigir mudanças em seu código. Isso não se aplica a COUNT(*). É muito raro querer o comportamento especializada que SELECT COUNT('group_id') lhe dá - normalmente você quer saber o número de registros. Isso é o que COUNT(*) é para, então usá-lo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top