Considere uma tabela de valores e hashes, assim:
+------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+----------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| val | char(9) | NO | | NULL | |
| val_hashed | char(50) | YES | | NULL | |
+------------+----------+------+-----+---------+----------------+
A consulta a seguir termina em 0,00 segundos:
SELECT * FROM hashes ORDER BY 1 DESC LIMIT 1;
No entanto, esta consulta leva 3 minutos e 17 segundos:
SELECT val FROM hashes ORDER BY 1 DESC LIMIT 1;
Vejo que, enquanto a consulta está sendo executada, a lista de processos a mostra como status Sorting result
. A situação é completamente reproduzível. Observe que há outro processo executando INSERT
operações na tabela continuamente.
Por que a consulta mais específica levaria mais tempo para ser executada do que a *
consulta? Sempre acreditei que as *
consultas deveriam ser evitadas especificamente por razões de desempenho.
mysql
performance
select
dotancohen
fonte
fonte
id
para encontrar a primeira linha. O segundo precisa classificar o resultado completo naval
coluna (não indexada) .ORDER BY NUMBER
sintaxe é propensa a erros.SELECT *
combinado com um índice de coluna em,ORDER BY
está ofuscando qual coluna está sendo classificada - outro motivo para evitar*
s ...*
não é explícito. Dizer "me dê todas as colunas e classifique pela terceira" é tão determinístico quanto dizer "vá ao supermercado e me diga quantos semáforos você passou"Respostas:
A frase
ORDER BY 1
refere-se a diferentes colunas; no primeiro seráid
, no segundoval
. Comoid
é a chave, ela será indexada eorder by
será uma quantidade trivial de trabalho. Paraorder by val
, no entanto, o sistema precisará recuperar todas as linhas, classificar a tabela completaval
e escolher apenas uma dessas linhas.Altere as duas consultas para
order by id
e acho que seus tempos de execução serão quase idênticos.fonte
A diferença de desempenho em sua consulta é bem explicada por MG. Vou abordar isso:
select *
não possui penalidades particulares por si só, é problemático quando usado indevidamente. Em uma consulta de tabela única, funciona muito bem. agora junte essa tabela a outra com 20 colunas e depois adicione junções a outras 5 tabelas com muitas colunas cada. Agora é um problema. O mesmo acontece com as pessoas que ensinam band-aid amplo "nunca fazem X" sem explicar o porquê.fonte
SELECT *
pode ser um problema mesmo para uma consulta de tabela única. Por exemplo,SELECT * FROM hashes ORDER BY val;
provavelmente fará uma varredura completa da tabela e, em seguida, uma classificaçãoSELECT val FROM hashes ORDER BY val;
fará apenas uma varredura completa do índice e nenhuma classificação (supondo que exista um índice em val). Portanto, nunca é demais selecionar apenas os resultados que precisamos.select(*)
for usado apenas como uma sub- seleção? Como é uma seleção incorporada, o MySQL não seria inteligente o suficiente para descobrir as colunas reais que precisam ser selecionadas?