Se eu precisar de apenas 2/3 colunas e consultar em SELECT *
vez de fornecê-las na consulta selecionada, há alguma degradação no desempenho em relação a mais / menos E / S ou memória?
A sobrecarga da rede pode estar presente se eu selecionar * sem necessidade.
Mas em uma operação de seleção, o mecanismo de banco de dados sempre extrai tupla atômica do disco ou apenas as colunas solicitadas na operação de seleção?
Se ele sempre puxa uma tupla, a sobrecarga de E / S é a mesma.
Ao mesmo tempo, pode haver um consumo de memória para remover as colunas solicitadas da tupla, se ele puxar uma tupla.
Portanto, se for esse o caso, selecione someColumn terá mais sobrecarga de memória do que a seleção *
sql
performance
Neel Basu
fonte
fonte
SELECT
consultas sejam executadas / processadas seja diferente de banco de dados para banco de dados.CREATE VIEW foo_view AS SELECT * FROM foo;
, adicione colunas à tabela foo mais tarde, essas colunas não aparecerão automaticamente no foo_view conforme o esperado. Em outras palavras, o*
nesse contexto se expande apenas uma vez (no momento da criação da exibição), não por SELECT. Por causa das complicações decorrentes da ALTER TABLE, eu diria que (na prática)*
é considerado prejudicial.Respostas:
Ele sempre puxa uma tupla (exceto nos casos em que a tabela foi verticalmente segmentada - dividida em partes de colunas); portanto, para responder à pergunta que você fez, não importa da perspectiva de desempenho. No entanto, por muitos outros motivos, (abaixo) você sempre deve selecionar especificamente as colunas que deseja, pelo nome.
Ele sempre puxa uma tupla, porque (em todos os fornecedores que RDBMS eu conheço), a estrutura subjacente de armazenamento em disco para tudo (incluindo dados da tabela) é baseada em páginas de E / S definidas (no SQL Server, por exemplo, cada página é 8 kilobytes). E toda leitura / gravação de E / S é feita por página. Ou seja, toda gravação ou leitura é uma página completa de dados.
Devido a essa restrição estrutural subjacente, uma consequência é que cada linha de dados em um banco de dados deve estar sempre em uma e apenas uma página. Ele não pode abranger várias páginas de dados (exceto para coisas especiais, como blobs, onde os dados reais do blob são armazenados em partes de página separadas e a coluna da linha da tabela real recebe apenas um ponteiro ...). Mas essas exceções são apenas isso, exceções, e geralmente não se aplicam, exceto em casos especiais (para tipos especiais de dados ou certas otimizações para circunstâncias especiais).
Mesmo nesses casos especiais, geralmente, a própria linha da tabela de dados (que contém o ponteiro para os dados reais do Blob, ou o que for), ele deve ser armazenado em uma única página de E / S.
EXCEÇÃO. O único local em que
Select *
está OK é na subconsulta após uma cláusulaExists
ouNot Exists
predicado, como em:EDIT: Para abordar o comentário de Mike Sherer, Sim, é verdade, tanto tecnicamente, com um pouco de definição para o seu caso especial e esteticamente. Primeiro, mesmo quando o conjunto de colunas solicitadas é um subconjunto daquelas armazenadas em algum índice, o processador de consultas deve buscar todas as colunas armazenadas nesse índice, não apenas as solicitadas, pelos mesmos motivos - TODAS as E / S devem ser feitas em páginas e dados de índice são armazenados nas páginas IO, assim como os dados da tabela. Portanto, se você definir "tupla" para uma página de índice como o conjunto de colunas armazenadas no índice, a instrução ainda será verdadeira.
e a afirmação é verdadeira esteticamente porque o ponto é que ele busca dados com base no que é armazenado na página de E / S, não no que você solicita, e isso é verdade se você está acessando a Página de E / S da tabela base ou um índice Página de E / S.
Por outras razões para não usar
Select *
, consulte Por que éSELECT *
considerado prejudicial? :fonte
select *
, terá menos sobrecarga de memória do que aselect column
mesma sobrecarga de E / S. Então, se deixarmos a sobrecarga da rede.select *
se menos sobrecarga do que a deselect column
Há vários motivos para você nunca (nunca) usar
SELECT *
no código de produção:como você não está dando dicas ao seu banco de dados sobre o que deseja, primeiro será necessário verificar a definição da tabela para determinar as colunas nessa tabela. Essa pesquisa custará algum tempo - não muito em uma única consulta - mas aumenta com o tempo.
se você precisar de apenas 2/3 das colunas, estará selecionando 1/3 de dados em excesso que precisam ser recuperados do disco e enviados pela rede
se você começar a confiar em certos aspectos dos dados, por exemplo, a ordem das colunas retornadas, poderá receber uma surpresa desagradável assim que a tabela for reorganizada e novas colunas forem adicionadas (ou removidas as existentes)
no SQL Server (não tenho certeza sobre outros bancos de dados), se você precisar de um subconjunto de colunas, sempre haverá uma chance de um índice não clusterizado estar cobrindo essa solicitação (contém todas as colunas necessárias). Com um
SELECT *
, você está desistindo dessa possibilidade desde o início. Nesse caso específico, os dados seriam recuperados das páginas de índice (se elas contiverem todas as colunas necessárias) e, portanto, a E / S do disco e a sobrecarga de memória seriam muito menos em comparação com a realização de umaSELECT *....
consulta.Sim, é necessário um pouco mais de digitação inicialmente (ferramentas como o SQL Prompt para SQL Server até o ajudarão lá) - mas esse é realmente um caso em que há uma regra sem exceção: nunca use SELECT * no seu código de produção. SEMPRE.
fonte
Where Exists (Select * From ...
) o uso deSelect *
certamente não é um problema e, em alguns círculos, é considerado uma prática recomendada.IF EXISTS(SELECT *...
é um caso especial - uma vez lá, nenhum dado é realmente recuperado, mas é apenas um cheque de existência, o SELECT * não é um problema lá ...Você deve sempre apenas
select
as colunas que realmente precisa. Nunca é menos eficiente selecionar menos em vez de mais e você também enfrenta menos efeitos colaterais inesperados - como acessar suas colunas de resultados no lado do cliente por índice e, depois, tornar esses índices incorretos adicionando uma nova coluna à tabela.[editar]: Significou acessar. Cérebro estúpido ainda acordando.
fonte
SELECT *
.A menos que você esteja armazenando grandes bolhas, o desempenho não é uma preocupação. O grande motivo para não usar SELECT * é que, se você estiver usando linhas retornadas como tuplas, as colunas retornarão na ordem que o esquema especificar, e se isso mudar, você precisará corrigir todo o seu código.
Por outro lado, se você usa o acesso no estilo de dicionário, não importa em que ordem as colunas retornam, porque você sempre as acessa pelo nome.
fonte
Isso imediatamente me faz pensar em uma tabela que eu estava usando que continha uma coluna do tipo
blob
; geralmente continha uma imagem JPEG, com algunsMb
s de tamanho.Escusado será dizer que eu não fiz
SELECT
essa coluna, a menos que eu realmente precisava. Ter esses dados flutuando - especialmente quando selecionei várias linhas - era apenas um aborrecimento.No entanto, admitirei que, de outra forma, normalmente consulta todas as colunas em uma tabela.
fonte
Durante uma seleção SQL, o banco de dados sempre se refere aos metadados da tabela, independentemente de ser SELECT * para SELECT a, b, c ... Por que? Porque é aí que estão as informações sobre a estrutura e o layout da tabela no sistema.
Ele precisa ler essas informações por dois motivos. Um, simplesmente compilar a declaração. Ele precisa garantir que você especifique uma tabela existente, no mínimo. Além disso, a estrutura do banco de dados pode ter sido alterada desde a última vez que uma instrução foi executada.
Agora, obviamente, os metadados do banco de dados são armazenados em cache no sistema, mas ainda é o processamento que precisa ser feito.
Em seguida, os metadados são usados para gerar o plano de consulta. Isso acontece sempre que uma declaração é compilada também. Novamente, isso é executado nos metadados armazenados em cache, mas sempre é feito.
O único momento em que esse processamento não é concluído é quando o banco de dados está usando uma consulta pré-compilada ou armazenou em cache uma consulta anterior. Este é o argumento para usar parâmetros de ligação em vez de SQL literal. "SELECT * FROM TABLE WHERE key = 1" é uma consulta diferente de "SELECT * FROM TABLE WHERE key =?" e o "1" é vinculado à chamada.
Os bancos de dados dependem muito do cache da página para que funcione. Muitos bancos de dados modernos são pequenos o suficiente para caber completamente na memória (ou, talvez eu deva dizer, a memória moderna é grande o suficiente para caber muitos bancos de dados). Então, o seu custo de E / S principal no back-end é o log e as descargas de página.
No entanto, se você ainda estiver pressionando o disco para o seu banco de dados, uma otimização primária feita por muitos sistemas é confiar nos dados nos índices, e não nas próprias tabelas.
Se você tem:
Então, se você selecionar "SELECT id, nome FROM customer WHERE id = 1", é muito provável que o banco de dados extraia esses dados do índice, e não das tabelas.
Por quê? Provavelmente, ele usará o índice de qualquer maneira para satisfazer a consulta (versus uma verificação de tabela) e, embora 'name' não seja usado na cláusula where, esse índice ainda será a melhor opção para a consulta.
Agora, o banco de dados tem todos os dados necessários para satisfazer a consulta, portanto, não há motivo para acessar as páginas da tabela. O uso do índice resulta em menos tráfego de disco, pois você tem uma densidade mais alta de linhas no índice versus a tabela em geral.
Esta é uma explicação manual de uma técnica de otimização específica usada por alguns bancos de dados. Muitos têm várias técnicas de otimização e ajuste.
No final, SELECT * é útil para consultas dinâmicas que você precisa digitar manualmente, eu nunca o usaria para "código real". A identificação de colunas individuais fornece ao banco de dados mais informações que ele pode usar para otimizar a consulta e oferece um controle melhor no seu código contra alterações de esquema etc.
fonte
Acho que não há uma resposta exata para sua pergunta, porque você está pensando no desempenho e na facilidade de manter seus aplicativos.
Select column
é mais performáticoselect *
, mas se você estiver desenvolvendo um sistema de objetos orientado, gostará de usarobject.properties
e poderá precisar de propriedades em qualquer parte dos aplicativos; precisará escrever mais métodos para obter propriedades em situações especiais, se não o fizer. useselect *
e preencha todas as propriedades. Seus aplicativos precisam ter um bom desempenho usandoselect *
e, em alguns casos, você precisará usar a coluna select para melhorar o desempenho. Então você terá o melhor de dois mundos, facilidade para escrever e manter aplicativos e desempenho quando precisar de desempenho.fonte
A resposta aceita aqui está errada. Me deparei com isso quando outra pergunta foi fechada como uma duplicata disso (enquanto eu ainda estava escrevendo minha resposta - grr -, portanto, o SQL abaixo faz referência à outra pergunta).
Você sempre deve usar o atributo SELECT, atributo .... NOT SELECT *
É principalmente para problemas de desempenho.
Não é um exemplo muito útil. Considere em vez disso:
Se houver um índice ativado (nome, telefone), a consulta poderá ser resolvida sem a necessidade de procurar os valores relevantes da tabela - há uma cobertura índice de .
Além disso, suponha que a tabela possua um BLOB contendo uma imagem do usuário, um CV carregado e uma planilha ... usando SELECT * reunirá todas essas informações nos buffers do DBMS (forçando outras informações úteis do cache). Em seguida, tudo será enviado ao cliente usando o tempo de funcionamento na rede e a memória no cliente para dados redundantes.
Também pode causar problemas funcionais se o cliente recuperar os dados como uma matriz enumerada (como mysql_fetch_array do PHP ($ x, MYSQL_NUM)). Talvez quando o código foi escrito 'phone' foi a terceira coluna a ser retornada por SELECT *, mas alguém aparece e decide adicionar um endereço de email à tabela, posicionado antes de 'telephone'. O campo desejado agora é deslocado para a quarta coluna.
fonte
Existem razões para fazer as coisas de qualquer maneira. Eu uso muito o SELECT * no PostgreSQL porque há muitas coisas que você pode fazer com o SELECT * no PostgreSQL que você não pode fazer com uma lista de colunas explícita, principalmente quando em procedimentos armazenados. Da mesma forma no Informix, SELECT * em uma árvore de tabela herdada pode fornecer linhas irregulares, enquanto uma lista explícita de colunas não pode, porque também são retornadas colunas adicionais nas tabelas filho.
A principal razão pela qual faço isso no PostgreSQL é que ele garante um tipo bem formado específico para uma tabela. Isso me permite pegar os resultados e usá-los como o tipo de tabela no PostgreSQL. Isso também permite muito mais opções na consulta do que uma lista rígida de colunas permitiria.
Por outro lado, uma lista rígida de colunas fornece uma verificação no nível do aplicativo, de que os esquemas de banco de dados não foram alterados de determinadas maneiras e isso pode ser útil. (Eu faço essas verificações em outro nível.)
Quanto ao desempenho, costumo usar VIEWs e procedimentos armazenados retornando tipos (e depois uma lista de colunas dentro do procedimento armazenado). Isso me dá controle sobre quais tipos são retornados.
Mas lembre-se de que estou usando SELECT * geralmente em uma camada de abstração em vez de em tabelas base.
fonte
Referência retirada deste artigo:
Sem SELECT *: quando você estiver usando "SELECT *" naquele momento, estará selecionando mais colunas do banco de dados e parte dessa coluna poderá não ser usada pelo seu aplicativo. Isso criará custos e cargas extras no sistema de banco de dados e mais dados serão transportados pela rede.
Com SELECT *: se você possui requisitos especiais e criou um ambiente dinâmico ao adicionar ou excluir uma coluna, manipule automaticamente pelo código do aplicativo. Nesse caso especial, você não precisa alterar o código do aplicativo e do banco de dados e isso afetará automaticamente o ambiente de produção. Nesse caso, você pode usar "SELECT *".
fonte
Apenas para adicionar uma nuance à discussão que não vejo aqui: Em termos de E / S, se você estiver usando um banco de dados com armazenamento orientado a colunas poderá fazer MUITO menos E / S se consultar apenas determinadas colunas. À medida que mudamos para SSDs, os benefícios podem ser um pouco menores do que o armazenamento orientado a linhas, mas há: a) apenas a leitura dos blocos que contêm colunas importantes para você; b) compactação, que geralmente reduz bastante o tamanho dos dados no disco e, portanto, o volume de dados lidos do disco.
Se você não está familiarizado com o armazenamento orientado a colunas, uma implementação do Postgres vem do Citus Data, outra é Greenplum, outra Paraccel, outra (em termos gerais) é o Amazon Redshift. Para o MySQL, existe o Infobright, o InfiniDB agora quase extinto. Outras ofertas comerciais incluem Vertica da HP, Sybase IQ, Teradata ...
fonte
igual
fonte