Ontem eu estava discutindo com um programador de "hobby" (eu mesmo sou um programador profissional). Nós encontramos alguns de seus trabalhos, e ele disse que sempre consulta todas as colunas em seu banco de dados (mesmo no / no servidor / código de produção).
Tentei convencê-lo a não fazê-lo, mas ainda não obtive tanto sucesso. Na minha opinião, um programador deve consultar apenas o que é realmente necessário em prol da "beleza", eficiência e tráfego. Estou enganado com a minha opinião?
Respostas:
Pense no que você está recebendo de volta e como vinculá-los às variáveis do seu código.
Agora pense no que acontece quando alguém atualiza o esquema da tabela para adicionar (ou remover) uma coluna, mesmo a que você não está usando diretamente.
Usar select * quando você digita consultas manualmente é bom, não quando você está escrevendo consultas para código.
fonte
Alterações de esquema
foo
, e outra tabela na consulta adicionar uma colunafoo
, a maneira como isso é tratado pode causar problemas ao tentar obter a coluna corretafoo
.De qualquer maneira, uma alteração no esquema pode causar problemas com a extração dos dados.
Considere ainda se uma coluna que estava sendo usada é removida da tabela. O
select * from ...
erro ainda funciona, mas ocorre um erro ao tentar extrair os dados do conjunto de resultados. Se a coluna é especificado na consulta, a consulta será erro para fora em vez dando um indiciation clara sobre o que e onde está o problema.Sobrecarga de dados
Algumas colunas podem ter uma quantidade significativa de dados associados a elas. A seleção de volta
*
puxará todos os dados. Sim, évarchar(4096)
isso que está nas 1000 linhas que você selecionou, dando a você mais 4 megabytes de dados possíveis que você não precisa, mas que são enviados de qualquer maneira.Relacionado à alteração do esquema, esse varchar pode não existir lá quando você criou a tabela, mas agora está lá.
Falha em transmitir a intenção
Quando você seleciona voltar
*
e obtém 20 colunas, mas precisa apenas de duas delas, não está transmitindo a intenção do código. Ao olhar para a consulta que é feita,select *
não se sabe quais são as partes importantes dela. Posso alterar a consulta para usar esse outro plano para torná-lo mais rápido, não incluindo essas colunas? Não sei porque a intenção do que a consulta retorna não é clara.Vamos analisar alguns problemas do SQL que exploram essas alterações de esquema um pouco mais.
Primeiro, o banco de dados inicial: http://sqlfiddle.com/#!2/a67dd/1
DDL:
SQL:
E as colunas que você receber de volta são
oneid=1
,data=42
,twoid=2
, eother=43
.Agora, o que acontece se eu adicionar uma coluna à tabela um? http://sqlfiddle.com/#!2/cd0b0/1
E os meus resultados da mesma consulta como antes são
oneid=1
,data=42
,twoid=2
, eother=foo
.Uma mudança em uma das tabelas interrompe os valores de ae, de
select *
repente, sua ligação de 'other' a um int gera um erro e você não sabe o porquê.Se, em vez disso, sua instrução SQL foi
A alteração na tabela um não teria interrompido seus dados. Essa consulta é executada da mesma forma antes e depois da alteração.
Indexação
Ao fazer um,
select * from
você está puxando todas as linhas de todas as tabelas que correspondem às condições. Mesmo mesas com as quais você realmente não se importa. Embora isso signifique a transferência de mais dados, há outro problema de desempenho oculto na pilha.Índices. (relacionado ao SO: como usar o índice na instrução select? )
Se você estiver retirando muitas colunas, o otimizador de plano de banco de dados pode desconsiderar o uso de um índice, porque você ainda precisará buscar todas essas colunas e levaria mais tempo para usar o índice e buscar todas as colunas na consulta do que seria apenas fazer uma verificação completa da tabela.
Se você está apenas selecionando o, digamos, sobrenome de um usuário (que você faz muito e tem um índice), o banco de dados pode fazer uma varredura apenas de índice (varredura apenas de índice postgres wiki , mysql full table vs vs full varredura de índice , varredura apenas de índice: evitando acesso à tabela ).
Há algumas otimizações sobre a leitura apenas de índices, se possível. As informações podem ser extraídas mais rapidamente em cada página de índice, porque você também extrai menos delas - não está inserindo todas as outras colunas da
select *
. É possível que uma varredura apenas de índice retorne resultados da ordem de 100x mais rápido (fonte: selecione * está incorreto ).Isso não quer dizer que uma varredura completa do índice seja ótima, ainda é uma varredura completa - mas é melhor que uma varredura de tabela completa. Quando você começa a perseguir todas as maneiras que
select *
prejudicam o desempenho, continua encontrando novas.Leitura relacionada
fonte
select *
?Outra preocupação: se é uma
JOIN
consulta e você está recuperando os resultados da consulta em uma matriz associativa (como pode ser o caso no PHP), é propenso a erros.A coisa e que
foo
tiver colunasid
ename
bar
tiver colunasid
eaddress
,SELECT * FROM foo JOIN bar ON foo.id = bar.id
adivinhe o que acontece quando alguém adiciona uma coluna
name
àbar
tabela.De repente, o código para de funcionar corretamente, porque agora a
name
coluna aparece nos resultados duas vezes e se você estiver armazenando os resultados em uma matriz, os dados de secondname
(bar.name
) substituirão o primeironame
(foo.name
)!É um bug bastante desagradável, porque é muito óbvio. Pode demorar um pouco para descobrir, e não há como a pessoa que adicionar outra coluna na tabela possa ter antecipado um efeito colateral indesejável.
(História real).
Portanto, não use
*
, controle as colunas que você está recuperando e use aliases quando apropriado.fonte
SELECT
cláusula, e é aí que, esperançosamente, você identifica o nome não exclusivo. BTW, eu não acho que seja tão raro em sistemas com grandes bancos de dados. Como eu disse, certa vez passei algumas horas caçando esse bug em um grande arquivo de código PHP. E eu encontrei um outro caso agora: stackoverflow.com/q/17715049/168719Consultar todas as colunas pode ser perfeitamente legítimo, em muitos casos.
Sempre consultar todas as colunas não é.
É mais trabalho para o seu mecanismo de banco de dados, que precisa disparar em torno de seus metadados internos para descobrir com quais colunas ele precisa lidar antes de continuar com o negócio real de realmente obter os dados e enviá-los de volta para você. OK, não é a maior sobrecarga do mundo, mas os catálogos de sistemas podem ser um gargalo apreciável.
É mais trabalho para sua rede, porque você está retirando qualquer número de campos quando pode querer apenas um ou dois deles. Se alguém [mais] vai e adiciona uma dúzia de campos extras, todos contendo grandes pedaços de texto, sua produtividade repentinamente passa pelo chão - sem motivo aparente. Isso fica pior se a sua cláusula "where" não for particularmente boa e você também estiver puxando muitas linhas - isso significa potencialmente muitos dados percorrendo a rede até você (isto é, será lento).
É mais trabalho para o seu aplicativo, ter que recuar e armazenar todos esses dados extras que provavelmente não se importam.
Você corre o risco de as colunas mudarem de ordem. OK, você não precisa se preocupar com isso (e não o fará se selecionar apenas as colunas de que precisa), mas, se for buscá-las todas de uma vez e alguém [mais] decidir reorganizar a ordem das colunas na tabela , que a exportação de CSV cuidadosamente elaborada que você dá para as contas no final do corredor repentinamente vai para o pote - novamente, sem motivo aparente.
BTW, eu disse "alguém [mais]" algumas vezes, acima. Lembre-se de que os bancos de dados são inerentemente multiusuário; você pode não ter o controle sobre eles que pensa ter.
fonte
TOP
limitação; Não tenho certeza do quanto isso é importante se o código lê quantos ele deseja exibir e depois descarta a consulta. Acho que as respostas às consultas são processadas um tanto preguiçosamente, embora eu não conheça os detalhes. De qualquer forma, acho que, em vez de dizer "não é legítimo", seria melhor dizer "... é legítimo em muito menos"; basicamente, resumiria os casos legítimos como aqueles em que o usuário teria uma idéia melhor do que é significativo para o programador.A resposta curta é: depende do banco de dados que eles usam. Os bancos de dados relacionais são otimizados para extrair os dados necessários de maneira rápida, confiável e atômica . Em conjuntos de dados grandes e consultas complexas, é muito mais rápido e provavelmente mais seguro que SELECTing * e faz o equivalente a junções no lado do 'código'. Os armazenamentos de valores-chave podem não ter essas funcionalidades implementadas ou podem não ter maturidade suficiente para serem usados na produção.
Dito isso, você ainda pode preencher qualquer estrutura de dados que estiver usando com SELECT * e elaborar o restante no código, mas encontrará gargalos de desempenho se desejar escalar.
A comparação mais próxima é a classificação dos dados: você pode usar quicksort ou bubblesort e o resultado estará correto. Mas não será otimizado e, definitivamente, terá problemas quando você introduzir simultaneidade e precisar classificar atomicamente.
Obviamente, é mais barato adicionar RAM e CPUs do que investir em um programador que pode fazer consultas SQL e tem até uma vaga compreensão do que é um JOIN.
fonte
Customer customer = this._db.Customers.Where( “it.ID = @ID”, new ObjectParameter( “ID”, id ) ).First();
Veja Tempo ofender na página 2.var cmd = db.CreateCommand(); cmd.CommandText = "SELECT TOP 1 * FROM Customers WHERE ID = @ID"; cmd.Parameters.AddWithValue("@ID", id); var result = cmd.ExecuteReader();
.... e, em seguida, prossiga para criar um cliente a partir de cada linha. LINQ supera isso.var customer = _db.Customers.Where(it => it.id == id).First();
.IMO, é sobre ser explícito vs implícito. Quando escrevo código, quero que funcione porque o fiz funcionar, não apenas porque todas as partes estão lá. Se você consultar todos os registros e seu código funcionar, você terá a tendência de seguir em frente. Posteriormente, se algo mudar e agora seu código não funcionar, é muito difícil depurar muitas consultas e funções procurando um valor que deveria estar lá e as únicas referências de valores são *.
Também em uma abordagem em camadas N, ainda é melhor isolar as interrupções do esquema do banco de dados na camada de dados. Se sua camada de dados estiver passando * para a lógica de negócios e provavelmente na camada de apresentação, você estará expandindo seu escopo de depuração exponencialmente.
fonte
select *
é muito pior!porque se a tabela obtém novas colunas, você obtém todas mesmo quando não precisa delas. com
varchars
isso pode se tornar muitos dados extras que precisam ser transportados do banco de dadosalgumas otimizações de banco de dados também podem extrair os registros de comprimento não fixo em um arquivo separado para acelerar o acesso às partes de comprimento fixo, usando select * anula o objetivo desse
fonte
Além da sobrecarga, algo que você deseja evitar em primeiro lugar, eu diria que, como programador, você não depende da ordem das colunas definida pelo administrador do banco de dados. Você seleciona cada coluna mesmo se precisar de todas elas.
fonte
Não vejo nenhuma razão para que você não deva usar para esse fim a construção - recupere todas as colunas de um banco de dados. Eu vejo três casos:
Uma coluna é adicionada no banco de dados e você deseja que ela também no código. a) Com * falhará com uma mensagem adequada. b) Sem * funcionará, mas não fará o que você espera, o que é muito ruim.
Uma coluna é adicionada no banco de dados e você não a deseja no código. a) Com * falhará; isso significa que * não se aplica mais, pois semântica significa "recuperar tudo". b) Sem * funcionará.
Uma coluna é removida O código falhará de qualquer maneira.
Agora, o caso mais comum é o caso 1 (desde que você usou *, o que significa tudo o que você provavelmente deseja); sem *, você pode ter um código que funcione bem, mas não faça o que se espera, o que é muito pior do que o código que falha com uma mensagem de erro adequada .
Não estou levando em consideração o código que recupera os dados da coluna com base no índice da coluna, que é propenso a erros na minha opinião. É muito mais lógico recuperá-lo com base no nome da coluna.
fonte
Select *
foi concebido mais como uma conveniência para consultas ad-hoc, não para fins de desenvolvimento de aplicativos. Ou para uso em construções estatísticas como aselect count(*)
que permite que o mecanismo de consulta decida se deseja usar um índice, qual índice usar e assim por diante e você não está retornando nenhum dado real da coluna. Ou para uso em cláusulas comowhere exists( select * from other_table where ... )
, que novamente é um convite ao mecanismo de consulta para escolher o caminho mais eficiente por si só e a subconsulta é usada apenas para restringir os resultados da consulta principal. Etc.select *
tem a semântica de recuperar todas as colunas; se o seu aplicativo realmente precisar disso, não vejo motivos para não usá-lo. Você pode apontar para alguma referência (Oracle, IBM, Microsoft etc.) que mencione o propósito para o qualselect *
foi criada não é recuperar todas as colunas?select *
existe para recuperar todas as colunas ... como um recurso de conveniência, para consultas ad-hoc, não porque é uma ótima idéia no software de produção. Os motivos já foram abordados muito bem nas respostas desta página, e é por isso que não criei minha própria resposta detalhada: •) Problemas de desempenho, organizando repetidamente dados na rede que você nunca usa; •) problemas com alias de coluna, •) falhas de otimização plano de consulta (não utilização de índices em alguns casos), •) servidor ineficiente I / O em casos onde limitado selecione poderia ter apenas índices utilizados, etc.select *
em um aplicativo de produção real, mas a natureza de um caso de borda é que não é o caso comum . :-)select *
; o que eu estava dizendo se você realmente precisa de todas as colunas, não vejo razão para não usarselect *
; embora poucos devam haver cenários em que todas as colunas sejam necessárias.Pense desta maneira ... se você consultar todas as colunas de uma tabela que possui apenas algumas sequências ou campos numéricos pequenos, esse total é de 100k de dados. Má prática, mas vai funcionar. Agora adicione um único campo que contém, digamos, uma imagem ou um documento do Word de 10mb. agora sua consulta de desempenho rápido imediatamente e misteriosamente começa a ter um desempenho ruim, apenas porque um campo foi adicionado à tabela ... talvez você não precise desse grande elemento de dados, mas porque o fez de
Select * from Table
qualquer maneira.fonte