Индексы MYSQL GROUP BY и WHERE, с отметкой времени - PullRequest
0 голосов
/ 19 октября 2018

Я реализовал этот запрос:

SELECT 
    evt.userId, evt.storeId, COUNT(1) AS totalVisits
FROM
    Event evt
WHERE
    evt.timestamp BETWEEN DATE_SUB(NOW(), INTERVAL 30 DAY) AND NOW()
    AND 
    evt.subtype = 2 
    AND 
    userID IS NOT NULL
GROUP BY userId, storeId
HAVING totalVisits>16;

Таблица событий содержит миллионы записей.Временная метка столбца - DATETIME, а остальные столбцы - INT.Эта таблица принимается очень часто и имеет много индексов.

В начале выполнение этого запроса занимало более 10 минут.Я решаю эту проблему, добавляя новый индекс

ALTER TABLE Event 
    ADD INDEX `Event_timestamp_subtype_userId_storeId` (`timestamp` ASC, `subType` ASC, `userId` ASC, `storeId` ASC);

. Это прекрасно работает, и у меня есть результаты менее чем за 2 секунды.

Проблема, с которой я сталкиваюсь, заключается в изменении условия INTERVAL 30 DAY.Если я установлю INTERVAL 50 DAY (например), MYSQL не будет использовать индекс, который я создал.Вместо этого он использует другой индекс, который охватывает только два столбца.

Команда объяснения:

EXPLAIN EXTENDED SELECT 
    evt.userId, evt.storeId, COUNT(1) AS totalVisits
FROM
    Event evt
WHERE
    evt.timestamp BETWEEN DATE_SUB(NOW(), INTERVAL 50 DAY) AND NOW()
    AND 
    evt.subtype = 2 
    AND 
    evt.userID IS NOT NULL
GROUP BY userId, storeId
HAVING totalVisits>16;

Объяснение ВЫХОД:

+----+-------------+-------+------------+------+------------------------------------------------------------------------------------------------------------+-----------------------------+---------+-------+---------+----------+---------------------------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys                                                                                              | key                         | key_len | ref   | rows    | filtered | Extra                                                               |
+----+-------------+-------+------------+------+------------------------------------------------------------------------------------------------------------+-----------------------------+---------+-------+---------+----------+---------------------------------------------------------------------+
|  1 | SIMPLE      | evt   | NULL       | ref  | Event_userId_index,Event_subType_storeId_index,Event_timetamp_index,Event_timestamp_subtype_userId_storeId | Event_subType_storeId_index | 3       | const | 7375964 |    25.00 | Using index condition; Using where; Using temporary; Using filesort |
+----+-------------+-------+------------+------+------------------------------------------------------------------------------------------------------------+-----------------------------+---------+-------+---------+----------+---------------------------------------------------------------------+

Итак, если поставить 50дни условие запрос является неизменным.Как я могу заставить этот запрос работать с правильными индексами независимо от значения параметров?

Я использую сервер mysql 5.7.23

Спасибо!

С уважением

1 Ответ

0 голосов
/ 20 октября 2018

У вас "много индексов".Дробовик не помогает.У вас есть эти индексы со столбцами в указанном порядке ?

INDEX(subtype, timestamp)
INDEX(subtype, userID)

Оптимизатору может потребоваться использовать любой из них для WHERE.И, поскольку он не может использовать все WHERE (из-за 2 диапазонов), он не попадет в столбцы в GROUP BY.

Первый столбец (subtype) протестирован с помощью =;это просто.
Второй столбец - это «диапазон», так что это последнее, с чем он может иметь дело.

Небольшое улучшение может быть достигнуто путем превращения каждого из этих индексов в «покрытие»index:

INDEX(subtype, timestamp, storeID, userID)
INDEX(subtype, userID, timestamp, storeID)

Теперь при обработке нужно взглянуть только на BTree индекса, и не нужно прыгать между этим BTree и тем, у которого есть данные.

(первые 2 столбца находятся вопределенный порядок; два других можно поменять местами.)

Если это «огромная» таблица (миллионы строк), мы можем поговорить о другой оптимизации, поскольку вам фактически нужен двумерный индекс.

...