Refatorei uma seção lenta de um aplicativo que herdamos de outra empresa para usar uma junção interna em vez de uma subconsulta como:
WHERE id IN (SELECT id FROM ...)
A consulta refatorada é executada 100x mais rápido. (~ 50 segundos para ~ 0,3) Eu esperava uma melhoria, mas alguém pode explicar por que foi tão drástico? As colunas usadas na cláusula where foram todas indexadas. O SQL executa a consulta na cláusula where uma vez por linha ou algo assim?
Atualização - Explique os resultados:
A diferença está na segunda parte da consulta "where id in ()" -
2 DEPENDENT SUBQUERY submission_tags ref st_tag_id st_tag_id 4 const 2966 Using where
vs 1 linha indexada com a junção:
SIMPLE s eq_ref PRIMARY PRIMARY 4 newsladder_production.st.submission_id 1 Using index
sql
mysql
performance
database-design
join
Palmsey
fonte
fonte
Respostas:
Uma "subconsulta correlacionada" (ou seja, aquela na qual a condição where depende dos valores obtidos das linhas da consulta que contém) será executada uma vez para cada linha. Uma subconsulta não correlacionada (aquela na qual a condição where é independente da consulta que contém) será executada uma vez no início. O mecanismo SQL faz essa distinção automaticamente.
Mas, sim, o plano de explicações fornecerá os detalhes sujos.
fonte
DEPENDENT SUBQUERY
significa exatamente a mesma coisa que "subconsulta correlacionada".Você está executando a subconsulta uma vez para cada linha, enquanto a junção acontece nos índices.
fonte
EXPLAIN
dizDEPENDENT SUBQUERY
, que é o indicador mais claro desse comportamento.Aqui está um exemplo de como as subconsultas são avaliadas no MySQL 6.0 .
O novo otimizador converterá esse tipo de subconsulta em junções.
fonte
Execute o plano de explicação em cada versão, ele mostrará o porquê.
fonte
antes que as consultas sejam executadas no conjunto de dados, elas são colocadas por meio de um otimizador de consultas, o otimizador tenta organizar a consulta de maneira que possa remover o máximo de tuplas (linhas) do conjunto de resultados o mais rápido possível. Freqüentemente, quando você usa subconsultas (especialmente más), as tuplas não podem ser removidas do conjunto de resultados até que a consulta externa comece a ser executada.
Sem ver a consulta, é difícil dizer o que há de tão ruim no original, mas meu palpite seria que era algo que o otimizador simplesmente não poderia melhorar muito. A execução de 'explicação' mostrará o método de otimização para recuperar os dados.
fonte
Veja o plano de consulta para cada consulta.
Onde in e Join geralmente podem ser implementados usando o mesmo plano de execução; portanto, normalmente não há aceleração zero entre as mudanças.
fonte
O Optimizer não fez um trabalho muito bom. Geralmente eles podem ser transformados sem nenhuma diferença e o otimizador pode fazer isso.
fonte
Geralmente, é o resultado do otimizador não conseguir descobrir que a subconsulta pode ser executada como uma junção; nesse caso, executa a subconsulta para cada registro da tabela, em vez de associá-la à subconsulta na tabela que você está consultando. Alguns dos bancos de dados mais "corporativos" são melhores nisso, mas às vezes ainda perdem isso.
fonte
Esta pergunta é um tanto geral, então aqui está uma resposta geral:
Basicamente, as consultas demoram mais quando o MySQL tem toneladas de linhas para classificar.
Faça isso:
Execute um EXPLAIN em cada uma das consultas (a que se juntou e depois a subconsultada) e publique os resultados aqui.
Eu acho que ver a diferença na interpretação do MySQL dessas consultas seria uma experiência de aprendizado para todos.
fonte
A subconsulta where deve executar 1 consulta para cada linha retornada. A junção interna apenas precisa executar 1 consulta.
fonte
A subconsulta provavelmente estava executando uma "verificação completa da tabela". Em outras palavras, não usando o índice e retornando muitas linhas que a Where da consulta principal estava precisando filtrar.
Apenas um palpite sem detalhes, é claro, mas essa é a situação comum.
fonte
Com uma subconsulta, você deve executar novamente o 2º SELECT para cada resultado, e cada execução normalmente retorna 1 linha.
Com uma junção, o segundo SELECT retorna muito mais linhas, mas você só precisa executá-lo uma vez. A vantagem é que agora você pode se unir aos resultados, e unir relações é o que um banco de dados deve ser bom. Por exemplo, talvez o otimizador possa identificar como aproveitar melhor um índice agora.
fonte
Não é tanto a subconsulta quanto a cláusula IN, embora as junções estejam na base do mecanismo SQL do Oracle e sejam executadas extremamente rapidamente.
fonte
Retirado do Manual de Referência ( 14.2.10.11 Reescrevendo subconsultas como junções ):
Portanto, as subconsultas podem ser mais lentas que LEFT [OUTER] JOINS.
fonte