Пожалуйста, помогите мне с анализом медленных запросов Mysql

StackOverflow https://stackoverflow.com/questions/2053757

Вопрос

У меня есть этот запрос mysql, который я пытаюсь проанализировать.Это очень медленно, таблица посетителей здесь содержит около 50 тысяч записей, этот запрос никогда не возвращается.Когда я попробовал использовать инструкцию explain, я обнаружил, что индекс не используется в таблице visitor, несмотря на то, что индекс доступен.Теперь это великая головоломка, которую мне нужна помощь в решении.Любые намеки приветствуются.

Запрос:

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'))

Поясняющий снимок выходного экрана:http://grab.by/grabs/9c3a629a25fc4e9ec0fa54355d4a092c.png

Это было полезно?

Решение

Из того, что я делаю вывод из вашего запроса, следующее должно привести к тому же результату, без подзапросов и с намного более высокой производительностью.

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;

Пожалуйста, объясните, если я что-то неправильно понял.Похоже, что ваш NOT IN предикат исключает любое Visitor идентификаторы, которые совпадают с любыми идентификаторами в Operator.То есть подзапрос генерирует список ВСЕ идентификаторы, которые есть в обеих таблицах, так что NOT IN условие эквивалентно внешнему соединению с Operator и простой тест , в котором o.ID IS NULL.

Это означает, что CASE выражение в вашем списке выбора бессмысленно, поскольку оно, безусловно, будет равно 0, если ваши условия совпадают только Visitor строки, которые не совпадают ни с какими строками в Operator.

Я думаю, что в вашем запросе что-то серьезно запутано.

Кроме того, похоже, что вы используете антипаттерн EAV в VisitorProfileField и ProfileField таблицы.Это доставит вам много хлопот.

Другие советы

Ваш запрос таков...большой.Можете ли вы объяснить, что это дает вам?Похоже, что он извлекает идентификатор каждого посетителя и определяет, являются ли они операторами, если они не являются операторами и у них есть определенные настройки профиля.В этом нет ни капли смысла, так что, должно быть, я чего-то здесь не понимаю.

Вот моя попытка, основанная на моем понимании того, что вы пытаетесь сделать:

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')

Объединенная таблица с именем "operator1_1_", похоже, не используется, вы должны быть в состоянии удалить это.Если вы используете его просто для того, чтобы убедиться, что в этой таблице есть запись для посетителя, я бы использовал exists вместо join .Я это уронил.

Я переключил ваш not на not exists, что, я думаю, может быть проще для MySQL оптимизировать.Я использовал IF вместо регистра, потому что у вас их всего два, и вводить их было короче.Я не знаю, работает ли какой-либо из них быстрее / проще в MySQL.

Я могу сказать вам, что, по моему опыту, производительность MySQL падает вместе с подзапросами в suqueries.Кажется, он отказывается от их оптимизации и начинает запускать их строка за строкой.Держу пари, что если бы вы использовали временную таблицу результатов (только для целей тестирования), вы бы обнаружили, что ваш запрос выполняется намного быстрее.

Редактировать:

Билл зашел дальше, чем я, а я зашел недостаточно далеко.Мне нравится вопрос Билла, и я согласен с его выводами по поводу изложения ДЕЛА, которые меня немного выбили из колеи.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top