Por favor me ajude com a análise de consulta Slow MySQL
-
20-09-2019 - |
Pergunta
Eu tenho essa consulta MySQL que estou tentando analisar. É muito lento, a tabela de visitantes aqui são cerca de 50 mil entradas, essa consulta nunca retorna. Quando tentei uma declaração de explicação, descobri que o índice não está sendo usado na tabela de visitantes, apesar do índice estar disponível. Agora este é o grande quebra -cabeça que preciso de ajuda para resolver. Quaisquer dicas apreciadas.
Consulta:
select distinct
visitor0_.ID as ID130_,
case when visitor0_1_.id is not null then 1 when
visitor0_.ID is not null then 0
end as clazz_
from Visitor visitor0_
left outer join Operator visitor0_1_ on visitor0_.ID=visitor0_1_.id
where (visitor0_.ID not in
(select operator1_.id
from Operator operator1_
inner join Visitor operator1_1_ on operator1_.id=operator1_1_.ID))
and (exists
(select visitorpro2_.ID
from VisitorProfileField visitorpro2_, ProfileField profilefie3_
where visitorpro2_.profileFieldID=profilefie3_.ID
and visitorpro2_.visitorID=visitor0_.ID
and profilefie3_.name='subscription86'
and visitorpro2_.numberVal=1
and visitorpro2_.stringVal='Manual'))
Explique a captura de tela de saída:http://grab.by/grabs/9c3a629a25fc4e9ec0fa54355d4a092c.png
Solução
Pelo que deduo da sua consulta, o seguinte deve produzir o mesmo resultado, sem subconsulta e desempenho muito mais rápido.
select v.ID as ID130_, 0 as clazz_
from Visitor v
left outer join (VisitorProfileField vpf join ProfileField pf
on vpf.profileFieldID = pf.ID)
on v.ID = vpf.visitorID and pf.name='subscription86'
and vpf.numberVal=1 and vpf.stringVal='Manual'
left outer join Operator o on v.ID = o.ID
where o.ID IS NULL;
Por favor, explique se eu entendi um pouco errado. Parece que o seu NOT IN
predicado exclui qualquer Visitor
ID que corresponde a qualquer ID está em Operator
. Isto é, a subconsência gera uma lista de tudo ID que está em ambas as tabelas, então o NOT IN
a condição é equivalente a uma união externa para Operator
e um teste simples onde o.ID IS NULL
.
Isso significa o CASE
A expressão na sua lista de seleção não tem sentido, pois certamente será 0 se suas condições corresponderem apenas Visitor
linhas que não correspondem a nenhuma linha em Operator
.
Eu acho que algo está seriamente confuso em sua consulta.
Além disso, parece que você está usando o Antipattern Eav no VisitorProfileField
e ProfileField
mesas. Isso vai causar muitos problemas.
Outras dicas
Você está consulta é ... grande. Você pode explicar o que isso atribui para você? Parece que ele puxa cada ID do visitante e se eles são ou não um operador, onde não são um operador e têm uma configuração de perfil específica. Isso não faz muito sentido, então devo estar perdendo algo lá.
Aqui está minha tentativa, com base na minha compreensão do que você está tentando fazer:
select distinct visitor.ID, IF(operator.id IS NOT NULL, 1, 0) AS clazz
from Visitor left outer join Operator on visitor.ID = operator.id
where not exists
(select 'x' from Operator OperatorTwo where OperatorTwo.id = visitor.ID)
and exists
(select 'x' from VisitorProfileField, ProfileField
where VisitorProfileField.profileFieldID = ProfileField.ID
and VisitorProfileField.profileFieldID.visitorID = visitor.ID
and VisitorProfileField.profileFieldID.numberVal = 1
and VisitorProfileField.profileFieldID.stringVal = 'Manual'
and ProfileField .name = 'subscription86')
A tabela ingressada chamada "Operator1_1_" não parece ser usada, você deve remover isso. Se você o estiver usando apenas para garantir que haja um registro para o visitante nessa tabela, eu usaria um existe em vez de uma junção. Eu deixei cair isso.
Eu desliguei você para não existir, o que acho que pode ser mais fácil para o MySQL otimizar. Eu usei um caso se em vez de um caso, porque você tem apenas dois e foi mais curto para digitar. Não sei se um deles é mais rápido/mais fácil no MySQL.
Posso dizer -lhe que, na minha experiência, o MySQL Performance morre com subconsciência em suformas. Parece desistir de otimizá -los e começa a executá -los de linha por linha. Aposto que, se você usasse uma tabela temporária de resultados (apenas para fins de teste), encontraria sua consulta muito mais rapidamente.
Editar:
Bill foi além do que eu, não fui longe o suficiente. Gosto da consulta de Bill e concordo com suas conclusões sobre a declaração do caso, que estava meio que me jogando.