Por hábito, nunca uso SELECT *
em código de produção (só uso com consultas de sucata ad-hoc, normalmente ao aprender o esquema de um objeto). Mas me deparei com um caso agora em que estou tentado a usá-lo, mas me sentiria barato se o fizesse.
Meu caso de uso está dentro de um procedimento armazenado onde é criada uma tabela temporária local que deve sempre corresponder à tabela subjacente usada para criá-la, sempre que o procedimento armazenado for executado. A tabela temporária é preenchida muito mais tarde, portanto, um truque rápido para criar a tabela temporária sem ser detalhado seria SELECT * INTO #TempTable FROM RealTable WHERE 1 = 0
especialmente para uma tabela com centenas de colunas.
Se o consumidor do meu procedimento armazenado for agnóstico para conjuntos de resultados dinâmicos, há algum problema comigo vendendo meus serviços para SELECT *
?
Eu geralmente abomino SELECT * no código de produção e já estive em uma situação em que seu uso levou a grandes quantidades de retrabalho posteriormente. No entanto, seu caso parece um uso justo.
O lugar onde acho SELECT * obrigatório - e seu primo malvado "INSERT INTO tbl" sem uma lista de colunas - está em uma situação de arquivamento, onde as linhas estão sendo movidas para outra tabela que deve ter a mesma estrutura.
Se uma nova coluna for adicionada a SalesOrder no futuro, mas não a SalesOrderArchive, o INSERT falhará. O que parece ruim, mas na verdade é uma coisa muito boa! Porque a alternativa é muito pior. Se todas as colunas estivessem listadas no INSERT e no SELECT, então o INSERT seria bem sucedido, assim como o DELETE a seguir (que é efetivamente "DELETE *"). O código de produção bem-sucedido não recebe nenhuma atenção e pode levar muito tempo até que alguém perceba que a nova coluna não está sendo arquivada, mas totalmente excluída silenciosamente.
IMO apenas coisas assim:
por exemplo
ou
ou seja, quando o
*
está vinculado a uma lista de colunas explícita que é declarada no mesmo lote e é usado apenas para evitar repetir a lista de colunas várias vezes.Quando o
*
se refere a uma tabela ou visualização, existem algumas complexidades desagradáveis sobre metadados em cache, por exemplo, aqui . E isso realmente não economiza a digitação, pois o SSMS permitirá que você arraste e solte a lista de colunas completa.Um uso válido de
SELECT *
ocorre quando introduzido porEXISTS
.Como todos os usos de
SELECT *
, isso tem o efeito colateral indesejado (e desnecessário aqui) de impedir queWITH SCHEMABINDING
seja adicionado se o código estiver dentro, por exemplo, de uma função.Perguntas e respostas relacionadas: EXISTS (SELECT 1 ...) vs EXISTS (SELECT * ...) Um ou outro?
Veja também:
Realmente, não há. No desenvolvimento das maneiras que você mencionou (selecione top n *), faz sentido, mas desenvolve maus hábitos e pode levar a problemas.
Você tocou no ponto principal sobre por que você não deve usá-lo, e essa é a estrutura da tabela real que pode mudar. Criar uma tabela temporária como você mencionou é tudo de bom, mas onde você pode chegar é mais tarde em seu proc, depois de preencher a tabela temporária com alguns
INSERT
comandos, você retorna o conjunto de resultados comSELECT *
. Agora, seu aplicativo final recuperaria colunas que não são esperadas.Você pode usar
SELECT ... INTO #TEMP FROM ...
para criar a tabela temporária em tempo real também. É meio difícil saber qual é o melhor para sua situação.A maioria dos outros problemas
SELECT *
não parecem importar para o seu caso de usoVou ser ousado e dizer: Existem casos de uso para SELECT * no código de produção. Sempre que você puder dizer "Quero que qualquer alteração na tabela seja refletida imediatamente em uma alteração na saída do meu resultado" é um caso para fazê-lo.
Deixe-me dar alguns exemplos:
...
Minha resposta à sua pergunta é "A maioria/muitos casos de uso"
Seus casos de uso destacam por que * não é horrível. Seu esquema será alterado. Por que se preparar para tocar em cada SP porque você precisa adicionar um campo?
Se você estiver adicionando um campo, por que minha interface do usuário se importaria? Se você estiver excluindo um campo, não importa se você usa * ou um CSV, você está introduzindo uma alteração importante.
"Se o consumidor do meu procedimento armazenado for agnóstico para conjuntos de resultados dinâmicos, ..."
Aqui está o verdadeiro problema com o uso select *. Se o seu consumidor for mal escrito, você poderá ter problemas. Por exemplo, se você estiver formatando Fields[13] como uma data...
Alguns casos em que eu evitaria selecionar *:
Mitigação de latência - Meu consumidor está distante e precisa apenas de um subconjunto relativamente pequeno de campos na(s) tabela(s)
Joins - Consulta complexa envolvendo várias tabelas. O consumidor provavelmente não precisa de todos os campos de todas as tabelas. Na verdade, existem colunas de chave duplicadas que provavelmente devem ser omitidas.
Eu sei que meus consumidores escrevem código ruim - Se você estiver desenvolvendo uma API pública, suponho que seja possível que você queira honrar o OpenClose e criar um novo método de API toda vez que o conjunto de campos for alterado. Para mim, isso parece uma abordagem ruim para o referido problema ...
Como em qualquer coisa com programação, há hora e lugar. Há sempre o conjunto da torre de marfim. Ouça seus pensamentos com uma mente aberta. Então decida-se.
depende do mecanismo de falha que você preferir.
Se, quando uma nova coluna for adicionada, ela sempre puder ser ignorada com segurança (por exemplo: selecione primeiro nome, sobrenome de clientes onde id=@x), então nunca use select * - quanto mais colunas você tocar, menor a chance de um índice útil pode ser encontrado/criado.
Se quando uma nova coluna for adicionada, o descarte silencioso dela for ruim (qualquer tipo de replicação de dados), então use uma seleção não especificada (insira em archiveTable select * from theTable where isOld=true) A falha de código aqui não é um bug, é é um recurso - especialmente no caso em que você controla o banco de dados e o código lendo a tabela.
Reverter os mecanismos de falha aqui é ruim - você não quer que sua pesquisa de nome falhe se adicionar uma nova cor favorita à pessoa.
você não quer ignorar o arquivamento da cor favorita da pessoa se a coluna foi adicionada depois que você escreveu o código de arquivamento.
Uma observação sobre junções - o sql server pulará a leitura de quaisquer colunas não usadas posteriormente
não toca em nada além das colunas firstname, id e email.