Оптимизируйте Query с MAX / MIN в предложении HAVING - PullRequest
0 голосов
/ 03 сентября 2018

У меня есть запрос, который занимает 17-20 секунд на нашем сервере, и я хотел бы посмотреть, что я могу сделать, чтобы оптимизировать его. MySQL 5.6 будет обновлен до 5.7 в ближайшие пару месяцев.

Запрос:

SELECT pm.mid AS mid
FROM 
pm_message pm
INNER JOIN pm_index pmi ON pmi.mid = pm.mid
GROUP BY pm.mid
HAVING  (MIN(pmi.deleted) > 0 AND MAX(pmi.deleted) < '1535490002') 
LIMIT 1000 OFFSET 0;

Средний столбец в pm_message и pm_index является первичным ключом в обеих таблицах. В таблице миллионы записей каждая

select count(*) from pm_message;
3748290

select count(*) from pm_index;
6938947

Есть предложения по улучшению этого запроса?

Мне интересно, поможет ли создание «удаленного» столбца в таблице pm_index для индекса?

Ответы [ 3 ]

0 голосов
/ 03 сентября 2018

Это уточняет ответ Shadows. Попробуйте использовать два not exists предложения:

SELECT pm.mid 
FROM pm_message pm
WHERE NOT EXISTS (SELECT 1
                  FROM pm_index pmi
                  WHERE pmi.mid = pm.mid AND 
                        pmi.deleted < 0
                 ) AND
      NOT EXISTS (SELECT 1
                  FROM pm_index pmi
                  WHERE pmi.mid = pm.mid AND 
                        pmi.deleted > 1535490002
                 ) ;

И убедитесь, что у вас есть индекс на pm_index(mid, deleted). Индекс очень важен. Я разбил его на две части, потому что OR может запутать оптимизатор запросов.

0 голосов
/ 13 сентября 2018

Дайте это попробовать. Это выворачивает вещи наизнанку - начиная с pmi, затем сводя к минимуму прикосновения к pm.

SELECT  mid, MIN(deleted) AS mind, MAX(deleted) AS maxd
    FROM  pm_index AS pmi
    GROUP BY  mid
    HAVING  mind > 0
      AND  maxd < '1535490002'
      AND  EXISTS (
            SELECT  1
                FROM  pm
                WHERE  mid = pmi.mid 
                  )
    LIMIT  1000 OFFSET 0;

Я сомневаюсь, что это сильно поможет - кажется, что запрос должен касаться практически всех строк в обеих таблицах.

Если все значения mid в pmi определенно существуют в pm, то моё предложение EXISTS может быть удалено. Однако вы говорите, что обе таблицы имеют PRIMARY KEY(mid)? Я подозреваю, что pmi на самом деле имеет второй столбец в PK. Пожалуйста, предоставьте SHOW CREATE TABLE.

0 голосов
/ 03 сентября 2018

Я бы полностью переписал запрос, потому что вы, в основном, хотите получить список различных средних значений, где удаленные находятся в пределах определенного диапазона. Вам не нужно отображать какие-либо данные из таблицы pm_index, поэтому я бы использовал коррелированный подзапрос с оператором not exists. Таким образом, mysql не нужно группировать и упорядочивать всю таблицу pm_index, чтобы получить минимальные и максимальные значения.

SELECT pm.mid AS mid
FROM 
pm_message pm
WHERE NOT EXISTS (SELECT 1 FROM pm_index WHERE pm_index.mid=pm.mid and (pm_index.deleted<0 OR pm_index.deleted>1535490002))

Для запроса будет полезен многоколонный индекс для средних и удаленных полей таблицы pm_index.

...