Antigamente, era considerado um grande não-não a fazer select * from table
ou select count(*) from table
por causa do desempenho atingido.
Esse ainda é o caso em versões posteriores do SQL Server (estou usando 2012, mas acho que a pergunta se aplica a 2008 - 2014)?
Edit: Como as pessoas parecem estar me criticando um pouco aqui, estou olhando para isso de um ponto de vista acadêmico/referente, não se é a coisa "certa" a fazer (o que obviamente não é)
Se você
SELECT COUNT(*) FROM TABLE
retornar apenas uma linha (a contagem), é relativamente leve e é o caminho para obter esse dado.E
SELECT *
não é um não-não físico, pois é legal e permitido.No entanto, o problema
SELECT *
é que você pode causar muito mais movimentação de dados. Você opera em todas as colunas da tabela. Se vocêSELECT
incluir apenas algumas colunas, poderá obter sua resposta de um índice ou índices, o que reduz a E/S e também o impacto no cache do servidor.Portanto, sim , não é recomendado como prática geral porque é um desperdício de seus recursos.
O único benefício real
SELECT *
é não digitar todos os nomes das colunas. Mas a partir do SSMS você pode arrastar e soltar para obter os nomes das colunas em sua consulta e excluir aquelas de que não precisa.Uma analogia: se alguém usa
SELECT *
quando não precisa de todas as colunas, também usariaSELECT
semWHERE
(ou alguma outra cláusula limitante) quando não precisa de todas as linhas?Além da resposta já fornecida, acho que vale a pena apontar que os desenvolvedores costumam ser muito preguiçosos ao trabalhar com ORMs modernos, como o Entity Framework. Enquanto os DBAs tentam ao máximo evitar
SELECT *
, os desenvolvedores geralmente escrevem o equivalente semanticamente, por exemplo, em c# Linq:Em essência, isso resultaria no seguinte:
Há também uma sobrecarga adicional que ainda não foi coberta. Esses são os recursos necessários para processar cada coluna em cada linha para o objeto relevante. Além disso, para cada objeto mantido na memória, esse objeto deve ser limpo. Se você selecionar apenas as colunas necessárias, poderá economizar facilmente mais de 100 MB de RAM. Embora não seja uma quantia enorme por conta própria, é o efeito cumulativo da coleta de lixo, etc., que é o custo do lado do cliente.
Então, sim, pelo menos para mim, é e sempre será um grande não. Também precisamos educar sobre os custos "ocultos" de fazer isso mais também.
Termo aditivo
Aqui está uma amostra de puxar apenas os dados que você precisa, conforme solicitado nos comentários:
Desempenho: uma consulta com SELECT * provavelmente nunca será uma consulta de cobertura ( Explicação de conversa simples, Explicação de estouro de pilha ).
À prova de futuro: sua consulta pode retornar todas as sete colunas hoje, mas se alguém adicionar cinco colunas no próximo ano, em um ano sua consulta retornará doze colunas, desperdiçando E/S e CPU.
Indexação: se você deseja que suas exibições e funções com valor de tabela participem da indexação no SQL Server, essas exibições e funções devem ser criadas com schemabinding, que proíbe o uso de SELECT *.
Prática recomendada : nunca use
SELECT *
em código de produção.Para subconsultas, prefiro
WHERE EXISTS ( SELECT 1 FROM … )
.Edit : Para abordar o comentário de Craig Young abaixo, usar "SELECT 1" em uma subconsulta não é uma "'otimização" - é para que eu possa ficar na frente da minha turma e dizer "não use SELECT *, sem exceções! "
A única exceção em que consigo pensar é onde o cliente está fazendo algum tipo de operação de tabela dinâmica e requer todas as colunas presentes e futuras.
Posso aceitar uma exceção envolvendo CTEs e tabelas derivadas, embora queira ver os planos de execução.
Observe que considero
COUNT(*)
uma exceção a isso porque é um uso sintático diferente de "*".No SQL Server 2012 (ou qualquer versão a partir de 2005), o uso
SELECT *...
é apenas um possível problema de desempenho na instrução SELECT de nível superior de uma consulta.Portanto, NÃO é um problema em Views (*), em subconsultas, em cláusulas EXIST, em CTEs, nem em
SELECT COUNT(*)..
etc., etc. Observe que isso provavelmente também é verdade para Oracle, DB2 e talvez PostGres (não tenho certeza) , mas é muito provável que ainda seja um problema em muitos casos para o MySql.Para entender por que (e por que ainda pode ser um problema em um SELECT de nível superior), é útil entender por que sempre foi um problema, porque usar
SELECT *..
significa " retornar TODAS as colunas ". Em geral, isso retornará muito mais dados do que você realmente deseja, o que obviamente pode resultar em muito mais IO, tanto no disco quanto na rede.O que é menos óbvio é que isso também restringe quais índices e planos de consulta um otimizador SQL pode usar, porque ele sabe que deve retornar todas as colunas de dados. Se ele pudesse saber com antecedência que você deseja apenas determinadas colunas, geralmente poderá usar planos de consulta mais eficientes, aproveitando os índices que possuem apenas essas colunas. Felizmente, há uma maneira de saber disso com antecedência, que é você especificar explicitamente as colunas que deseja na lista de colunas. Mas quando você usa "*", você está abrindo mão disso em favor de "apenas me dê tudo, vou descobrir o que preciso".
Sim, também há uso adicional de CPU e memória para processar cada coluna, mas quase sempre é menor em comparação com essas duas coisas: o disco extra significativo e a largura de banda de rede necessária para colunas que você não precisa e ter que usar menos plano de consulta otimizado porque precisa incluir todas as colunas.
Então o que mudou? Basicamente, os SQL Optimizers incorporaram com sucesso um recurso chamado "Otimização de coluna", que significa apenas que agora eles podem descobrir nas subconsultas de nível inferior se você realmente usará uma coluna nos níveis superiores da consulta.
O resultado disso é que não importa mais se você usar 'SELECT *..' nos níveis inferiores/internos de uma consulta. Em vez disso, o que realmente importa é o que está na lista de colunas do SELECT de nível superior. A menos que você use
SELECT *..
no topo, então, mais uma vez, deve assumir que você deseja TODAS as colunas e, portanto, não pode empregar otimizações de coluna de forma eficaz.(* -- observe que há um problema de ligação menor e diferente nas exibições
*
em que nem sempre registram a alteração nas listas de colunas quando "*" é usado. Existem outras maneiras de resolver isso e isso não afeta o desempenho.)Há mais um pequeno motivo para não usar
SELECT *
: se a ordem das colunas retornadas mudar, seu aplicativo irá quebrar... se você tiver sorte. Caso contrário, você terá um bug sutil que pode passar despercebido por muito tempo. A ordem dos campos em uma tabela é um detalhe de implementação que nunca deve ser considerado pelos aplicativos, pois a única vez que fica visível é se você usar um arquivoSELECT *
.É fisicamente e problemático usar
select * from table
, no entanto, é uma má ideia. Por quê?Em primeiro lugar, você descobrirá que está retornando colunas desnecessárias (recursos pesados).
Em segundo lugar, levará mais tempo em uma tabela grande do que nomear as colunas porque, quando você seleciona *, na verdade está selecionando os nomes das colunas do banco de dados e dizendo "me dê os dados associados às colunas que têm nomes nesta outra lista ." Embora isso seja rápido para o programador, imagine fazer essa pesquisa no computador de um banco que pode ter literalmente centenas de milhares de pesquisas em um minuto.
Em terceiro lugar, fazer isso torna as coisas mais difíceis para o desenvolvedor. Com que frequência você precisa alternar do SSMS para o VS para obter todos os nomes das colunas?
Em quarto lugar, é um sinal de programação preguiçosa e não acho que nenhum desenvolvedor queira essa reputação.
Pode ser um problema se você colocar o
Select * ...
código em um programa, porque, como apontado anteriormente, o banco de dados pode mudar com o tempo e ter mais colunas do que você esperava quando escreveu a consulta. Isso pode levar à falha do programa (na melhor das hipóteses) ou o programa pode seguir seu caminho alegre e corromper alguns dados porque está examinando valores de campo para os quais não foi escrito. Resumindo, o código de produção SEMPRE deve especificar os campos a serem retornados no arquivoSELECT
.Dito isso, tenho menos problema quando o
Select *
faz parte de umaEXISTS
cláusula, pois tudo o que vai ser retornado ao programa é um booleano indicando o sucesso ou falha do select. Outros podem discordar dessa posição e eu respeito a opinião deles sobre isso. PODE ser um pouco menos eficiente codificarSelect *
do que codificar 'Selecionar 1' em umaEXISTS
cláusula, mas não acho que haja perigo de corrupção de dados, de qualquer maneira.Muitas respostas por que
select *
está errado, então cobrirei quando achar que está certo ou pelo menos OK.1) Em um EXISTS, o conteúdo da parte SELECT da query é ignorado, então você pode até escrever
SELECT 1/0
e não vai dar erro.EXISTS
apenas verifica se alguns dados retornariam e retorna um booleano com base nisso.2) Isso pode iniciar uma tempestade de fogo, mas gosto de usar
select *
gatilhos em minha tabela de histórico. Porselect *
, evita que a tabela principal obtenha uma nova coluna sem adicionar a coluna à tabela de histórico, bem como por erros imediatos ao inserir/atualizar/excluir na tabela principal. Isso evitou várias vezes que os desenvolvedores adicionassem colunas e se esquecessem de adicioná-las à tabela de histórico.