MySQL подзадна замедляется, но они отлично работают самостоятельно

dba.stackexchange https://dba.stackexchange.com/questions/14565

Вопрос

Запрос 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).

  1. У вас есть индекс на Account_ID?

  2. Вторая проблема может быть с вложенными подзадатами, которые имеют ужасную производительность в 5,0.

  3. Группа с наличием пункта быстрее, чем отличается.

  4. Что вы пытаетесь сделать, что может быть лучше сделано через объединения в дополнение к пункту № 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с dba.stackexchange
scroll top