MySQL подзадна замедляется, но они отлично работают самостоятельно
-
16-10-2019 - |
Вопрос
Запрос 1:
select distinct email from mybigtable where account_id=345
занимает 0,1 с
Запрос 2:
Select count(*) as total from mybigtable where account_id=123 and email IN (<include all from above result>)
занимает 0,2 с
Запрос 3:
Select count(*) as total from mybigtable where account_id=123 and email IN (select distinct email from mybigtable where account_id=345)
занимает 22 минуты и 90% его в «подготовленном» состоянии. Почему это занимает так много времени.
Таблица иннодб с 3,2 -миллионными рядами на MySQL 5.0
Решение
В запросе 3 вы в основном выполняете подбору для каждой строки Mybigtable против себя.
Чтобы избежать этого, вам нужно внести два основных изменения:
Основное изменение № 1: Рефактор запроса
Вот ваш оригинальный запрос
Select count(*) as total from mybigtable
where account_id=123 and email IN
(select distinct email from mybigtable where account_id=345)
Вы могли бы попробовать
select count(*) EmailCount from
(
select tbl123.email from
(select email from mybigtable where account_id=123) tbl123
INNER JOIN
(select distinct email from mybigtable where account_id=345) tbl345
using (email)
) A;
Или, может быть, счет за электронное письмо
select email,count(*) EmailCount from
(
select tbl123.email from
(select email from mybigtable where account_id=123) tbl123
INNER JOIN
(select distinct email from mybigtable where account_id=345) tbl345
using (email)
) A group by email;
Основное изменение № 2: правильная индексация
Я думаю, что у вас уже есть, так как запрос 1 и Query 2 бегут быстро. Убедитесь, что у вас есть составной индекс (Account_ID, электронная почта). Делать SHOW CREATE TABLE mybigtable\G
И убедитесь, что у вас есть. Если у вас его нет или если вы не уверены, то все равно создайте индекс:
ALTER TABLE mybigtable ADD INDEX account_id_email_ndx (account_id,email);
Обновление 2012-03-07 13:26 EST
Если вы хотите сделать не в (), измените INNER JOIN
в LEFT JOIN
и проверьте, что правая сторона является нулевой, как это:
select count(*) EmailCount from
(
select tbl123.email from
(select email from mybigtable where account_id=123) tbl123
LEFT JOIN
(select distinct email from mybigtable where account_id=345) tbl345
using (email)
WHERE tbl345.email IS NULL
) A;
Обновление 2012-03-07 14:13 EST
Пожалуйста, прочитайте эти две ссылки на выполнение соединений
Вот отличное видео на YouTube, где я научился рефакторировать запросы и книга, на которой она была основана
Другие советы
В MySQL подэлекции в пункте IN в пункте пересматриваются для каждой строки во внешнем запросе, создавая тем самым O (n^2). Краткое рассказ: не используйте в (SELECT).
У вас есть индекс на Account_ID?
Вторая проблема может быть с вложенными подзадатами, которые имеют ужасную производительность в 5,0.
Группа с наличием пункта быстрее, чем отличается.
Что вы пытаетесь сделать, что может быть лучше сделано через объединения в дополнение к пункту № 3?
При обработке () такого подзадна () такого подластики () такого как ваш. Вы можете прочитать больше об этом здесь.
Моим первым предложением было бы попытаться переписать подложку в объединение. Что -то вроде (не проверено):
SELECT COUNT(*) AS total FROM mybigtable AS t1
INNER JOIN
(SELECT DISTINCT email FROM mybigtable WHERE account_id=345) AS t2
ON t2.email=t1.email
WHERE account_id=123