Problema de desempenho ao usar o SELECT *?

Duplicar Possível:
Qual é mais rápido / melhor? SELECT * ou SELECT column1, colum2, column3, etc
Qual é o motivo para não usar o select *?

Existe algum problema de desempenho no uso de SELECT * em vez de SELECT FiledName, FiledName2 …?

Se você precisa de um subconjunto das colunas, você está dando uma ajuda ruim para o otimizador (não pode escolher por índice, ou não pode ir apenas para o índice, …)

Alguns bancos de dados podem optar por recuperar dados apenas de índices. Essa coisa é muito muito útil e dá uma incrível aceleração. Executar as consultas SELECT * não permite esse truque.

De qualquer forma, do ponto de vista da aplicação não é uma boa prática.


Exemplo sobre isso:

  • Você tem uma mesa T com 20 colunas (C1, C2, …, C19 C20).
  • Você tem um índice em T para (C1, C2)
  • Você faz SELECT C1, C2 FROM T WHERE C1=123
  • O otimizador tem todas as informações no índice, não precisa ir para a tabela Data

Em vez disso, se você SELECT * FROM T WHERE C1=123 , o otimizador precisa obter todos os dados das colunas, então o índice em (C1, C2) não pode ser usado.

Em joins para várias tabelas é muito útil.

Dê uma olhada neste post:

Qual é o motivo para não usar o select *?

e esses:

  • Benefício de desempenho quando a consulta SQL é limitada ao chamar linha inteira
  • Qual é mais rápido ou melhor, selecione * ou selecione column1 colum2 column3
  • Pergunta de consulta SQL selecione * na visualização ou selecione col1 col2 col3 na visualização
  • Qual é mais rápido, selecione * ou selecione column1 column2 etc

Toda vez que você faz um select *, pode haver uma consulta adicional para obter a lista de colunas. Em ambientes de transactions elevadas, isso pode se tornar uma sobrecarga visível, mas, de vez em quando, não fará diferença.

Além disso, ao inserir registros, nunca use select * em uma inserção, caso as colunas sejam adicionadas.

O único problema de desempenho será se o seu aplicativo precisar apenas de um subconjunto dos campos retornados por select * . Não há diferença de desempenho no database, pois são efetivamente a mesma coisa.

Eu não sou um DBA, mas pelo que me lembro de aprender com nosso DBA, o raciocínio (pelo menos com o SQL Server) é que os algoritmos de cache de database não armazenam em cache ‘*’ consultas bem, mas se você estiver executando a mesma consulta com colunas exatas especificadas várias vezes, ele será armazenado em cache.

Tenho certeza de que um DBA mais experiente poderia entrar nos detalhes exatos de como funciona o mecanismo de armazenamento em cache, mas é por isso que há um impacto no desempenho.

OBSERVAÇÃO: O desempenho de armazenamento em cache só funciona se a consulta for executada várias vezes, especialmente em um período de tempo pequeno. Caso contrário, você não verá nenhuma diferença de desempenho.

Eu não sei sobre o desempenho de computação, mas em termos de capacidade de leitura / manutenção (ou seja, desempenho humano) não usamos select * na minha loja. Tudo é explicitamente selecionado.

Talvez. Depende em grande parte do mecanismo de database, como ele armazena coisas, quantas linhas estão voltando, quantas outras colunas existem e os tamanhos das outras colunas.

Se você estiver usando um database baseado em linhas (ou seja, a maioria deles) que armazena todas as colunas juntas (quase todas, exceto para BLOBs que são frequentemente armazenados separadamente, especialmente os maiores), então fazer SELECT * tem pouco impacto no próprio servidor – ele tem que buscar a linha inteira de qualquer maneira.

Por outro lado, se você está enviando os dados através de uma rede (ou mesmo localmente, pois isso afetará o tamanho dos buffers usados, etc.), então pode ajudar a ter menos colunas, pois haverá menos bytes para enviar costas. Essa diferença poderia ser ofuscada de qualquer maneira pelo desempenho do servidor se a consulta fosse de alguma forma difícil (por exemplo, requeria E / S).

Se você tem grandes bolhas nas linhas, SELECT * não é muito inteligente – caso contrário, é improvável que faça muita diferença, mas poderia.

Existem alguns mecanismos de database baseados em colunas – eles são completamente diferentes – para eles, “SELECT *” é um matador de desempenho total; não se esqueça de evitá-lo. As chances são, se você estiver usando um, você está completamente ciente disso (normalmente eles são usados ​​para aplicativos de datawarehouse muito grandes).

Para mim, a principal vantagem de não usar “SELECT *” é a manutenção. Você não tem surpresas quando alguém adiciona colunas extras à mesa; sua consulta “falha rapidamente” quando alguém remove uma das colunas que você estava usando. Isso torna o código mais auto-documentável, já que alguém pode ver quais colunas deseja.

Se todos os campos forem especificados, não, não deverá haver uma diferença significativa no desempenho. Mas se você quer apenas alguns campos específicos de uma tabela com uma dúzia de colunas, é mais lento.

Existem problemas de legibilidade e manutenção com o SELECT * . Faz sentido usar nomes de campo específicos o tempo todo, mesmo se você quiser selecionar todos os campos.

Desempenho, não muito. É um pouco desajeitado: em uma tabela, digamos, com 10 colunas, unidas em outras duas tabelas ou mais, particularmente com grandes conjuntos de resultados, o SELECT * pode retornar dezenas de colunas, geralmente com dados não utilizados ou até inúteis. Em termos do impacto no SGBD, não haveria muito, mas todos esses dados ainda precisam atravessar o fio de alguma forma; largura de banda de rede e latências conseqüentes certamente se summ. Eu vi isso em primeira mão em ambientes de alto volume. Isso definitivamente importa.

Além dos problemas de largura de banda, você também pode se deparar com problemas ambíguos de nomeação de colunas (desambiguar geralmente significa remover o SELECT * de qualquer forma, então você deve fazê-lo desde o início), e também é considerada boa prática ser explícita sobre as necessidades de o código dentro do código; isso ajuda de várias maneiras – com debugging, colaboração, etc.

Se você usar select * em uma junit, enviará automaticamente mais informações do que as necessárias, porque os campos de junit são repetidos. Isso é um desperdício de tempo de processamento e resources de rede e pode causar problemas de desempenho. Além disso, não especificar os campos significa que seu aplicativo pode quebrar quando novos campos são adicionados, especialmente se forem campos que o usuário não pretende ver, mas que estão lá para auditoria ou processamento de tipo de database. Selecionar * em uma inserção é sempre uma má idéia, já que em algum lugar ao longo da linha, alguns que não são espertos podem realmente alterar a ordem das colunas na tabela.

SELECT * é traduzido para SELECT Field1, Field2 …. etc antes de ser executado, de modo que sejam efetivamente a mesma coisa. Nenhuma diferença no desempenho.

No entanto, a legibilidade e a capacidade de manutenção são melhores quando o campo SELECT1, Field2 …

Tecnicamente, isso dependeria do sistema de gerenciamento de database relacional que você está usando. Eu acho que o impacto no desempenho seria de microssegundos. Se você está absolutamente tentando extrair o último pedaço de desempenho do seu sistema, eu diria que não usá-los.

Eu pessoalmente uso isso o tempo todo.

Supostamente sim. Estou totalmente contente no trabalho que eu nunca deveria usar o SELECT *. Na verdade, é nossa política não usá-lo porque a) significa que há ambiguidade no que é usado e o que está disponível apenas olhando para a consulta e b) é mais lento porque o SQL Server precisa encontrar cada coluna necessária e retorná-las .

Eu nunca vi nenhuma prova disso, no entanto.

EDIT : Além disso, se um procedimento armazenado é compilado no servidor e usa SELECT *, quando a estrutura de tabela subjacente é alterada supostamente não selecionará de volta as colunas introduzidas recentemente como SQL compila SELECT * para baixo para as colunas individuais.

Se você estiver usando apenas um subconjunto dos campos, a diferença de desempenho poderá ser substancial. Veja o exemplo a seguir, que envolve a recuperação de 1.411.771 linhas da análise do código Linux do CScout .

 $ time sh -c "echo 'select * from IDS' | mysql cslinux >/dev/null" real 0m5.622s user 0m2.580s sys 0m0.532s $ time sh -c "echo 'select EID from IDS' | mysql cslinux >/dev/null" real 0m4.492s user 0m0.716s sys 0m0.096s 

Isso não está nem medindo o impacto no desempenho do servidor.

Se você incorporar o sql no código, deverá usar sempre o formulário longo para fins de clareza, não para desempenho. Para consultas ad-hoc, a syntax select * é ESSENCIALMENTE não menos eficiente do que a especificação de nomes de colunas, a menos que você tenha um número massivo de colunas que você não deveria, a menos que você esteja desnormalizando.

Eu deveria ter 1 ponto por usar 2 excees em uma sentença e ainda assim fazer sentido !! 🙂

SELECT * requer SQL para encontrar todos os nomes das colunas, mas este não é o maior desempenho atingido por um longo tiro.

O maior impacto no desempenho de uma instrução SELECT * é quando você está executando uma consulta que requer um índice não-clusterizado para avaliar. Mesmo que o índice não-clusterizado seja um índice de cobertura de todas as colunas, o SQL ainda procurará a chave primária e obterá os valores do índice clusterizado.

Além disso, se você precisar apenas de uma ou duas colunas, o gargalo da rede será resolvido devido ao retorno de um conjunto de resultados maior do que o necessário.

Eu irei ecoar o que os outros disseram sobre “select *”, recuperando uma lista de colunas como parte do tratamento da requisição. Por outro lado, você também pode selecionar colunas por ordinal, o que economiza ainda mais tempo, já que o mecanismo RDBMS nem precisa procurar a coluna para determinar a posição da coluna a ser recuperada. Acho isso muito útil para consultas agregadas.

Por exemplo: selecione count (1) de … versus select count (*) from …

Neste exemplo, o RDBMS só precisa saber que precisa da contagem da primeira coluna e ZING está desativado. Na (infelizmente) contagem de seleção (*) mais comum, o RDBMS recupera uma lista de todas as colunas e, em seguida, verifica cada linha para determinar se é válida para a contagem (em vez de validar apenas a primeira coluna).

Isso funciona muito bem na maior parte do tempo. Tenho certeza de que a maioria dos sistemas DB conta valores NULL na contagem, mas você deve ficar atento a isso e verificar antes de assumir.

YMMV, nulo onde proibido, etc!

Desempenho Isso sempre será ruim se você não precisar de todas as colunas. Retornar mais dados do que o necessário limitará o database e sua largura de banda de lan / wan.

Legibilidade Sabendo quais colunas estão na visão, o procedimento pode ser muito útil, SELECT * não é de todo útil e eu consideraria isso contraproducente.

* Testando Se você fizer uma mudança de esquema, todo o seu código que usa SELECT * deve ser invalidado porque qualquer teste que você escrever para verificar metadados deve verificar a saída da visualização, proc.

* Claro, supondo que você tenha testes no lugar como todos os bons DB Dev’s devem ter 🙂

Eu concordo com quase todas as respostas, exceto certas afirmações de desempenho. Se você for realmente usar todas as colunas na tabela, eu diria que a versão SELECT * é um pouquinho mais rápida. Aqui está o porquê:

Tome essas duas consultas em uma tabela onde há um índice exclusivo em (id, x):

 SELECT x,y,z,w FROM tab WHERE id='abc' ORDER BY s SELECT x,y,z,w FROM tab WHERE id='abc' AND x in ('a','b','c','d','e','f','g','h',...) ORDER BY ('a','b','c','d','e','f','g','h',...) 

O que é mais rápido? Se a cláusula ‘x in’ nomear todos os valores de x na tabela para id ‘abc’, a primeira consulta provavelmente será mais rápida. Agora vamos renomear esses campos:

 SELECT field_name, field_type, field_offset, field_len FROM internal_field_catalog WHERE table_name = 'abc' ORDER BY field_order 

Portanto, ao recuperar os dados, o SELECT * permite que o mecanismo faça (o equivalente a) uma única memcpy para mover os dados da linha para o conjunto de resultados e, ao recuperar os dados do campo, provavelmente ele seja selecionado mais rapidamente.

Tudo o que estou dizendo é que existe um caso de borda onde o SELECT * é perfeitamente útil e provavelmente mais rápido. Uma razão pela qual você pode sempre precisar de todas as colunas de uma tabela é ao armazenar a persistência de objects em um RDBMS (por algum motivo). Para cada regra, há uma exceção.