Aqui está um cenário que surgiu recentemente no trabalho.
Considere três tabelas, A, B, C.
A tem 3.000 linhas; B tem 300.000.000 de linhas; e C tem 2.000 linhas.
As chaves estrangeiras são definidas: B (a_id), B (c_id).
Suponha que você tenha uma consulta semelhante a esta:
select a.id, c.id
from a
join b on b.a_id = a.id
join c on c.id = b.c_id
Na minha experiência, o MySQL pode escolher ir C -> B -> A neste caso. C é menor que A e B é enorme, e são todos equijoins.
O problema é que o MySQL não leva necessariamente em consideração o tamanho da interseção entre (C.id e B.c_id) vs (A.id e B.a_id). Se a junção entre B e C retornar tantas linhas quanto B, então é uma escolha muito ruim; se começar com A tivesse filtrado B para tantas linhas quanto A, então teria sido uma escolha muito melhor. straight_join
pode ser usado para forçar este pedido desta forma:
select a.id, c.id
from a
straight_join b on b.a_id = a.id
join c on c.id = b.c_id
Agora a
deve ser unido antes b
.
Geralmente você deseja fazer suas junções em uma ordem que minimize o número de linhas no conjunto resultante. Portanto, começar com uma mesa pequena e unir de forma que a união resultante também seja pequena é o ideal. As coisas ficam em forma de pêra se começar com uma mesa pequena e juntá-la a uma mesa maior acaba tão grande quanto a mesa grande.
Porém, é dependente de estatísticas. Se a distribuição de dados mudar, o cálculo pode mudar. Também depende dos detalhes de implementação do mecanismo de junção.
Os piores casos que eu vi para o MySQL em que tudo, exceto a straight_join
sugestão de índice exigida ou agressiva, são consultas que paginam sobre uma grande quantidade de dados em uma ordem de classificação estrita com filtragem leve. O MySQL prefere usar índices para quaisquer filtros e junções em vez de classificações; isso faz sentido porque a maioria das pessoas não está tentando classificar o banco de dados inteiro, mas tem um subconjunto limitado de linhas que respondem à consulta, e classificar um subconjunto limitado é muito mais rápido do que filtrar a tabela inteira, não importa se ela está classificada ou não. Nesse caso, colocar uma junção direta imediatamente após a tabela que tinha a coluna indexada que eu queria classificar em coisas fixas.
straight_join
.