Я просто создал таблицу с:
CREATE TABLE 'table_test' (
'time' date NOT NULL,
'line_id' char(36) NOT NULL,
'location_id' char(36) NOT NULL,
'placement_id' char(36) NOT NULL,
'flight_id' char(36) NOT NULL,
'impressions' int(11) DEFAULT '0',
PRIMARY KEY ('time','line_id','location_id','placement_id','flight_id'),
KEY 'table_test_IDX' ('time','placement_id','line_id','impressions') USING
BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Затем, когда я пытаюсь выполнить запрос:
SELECT
time,
placement_id,
line_id,
SUM(impressions) AS totalImpress
FROM
table_test
WHERE
time BETWEEN '2017-11-01' AND '2017-11-30'
GROUP BY time , placement_id , line_id;
Он всегда использует Using where; Using temporary; Using filesort
Using where; Using temporary; Using filesort
Using where; Using temporary; Using filesort
, в этом случае я хочу, чтобы запрос использовал table_test_IDX
.
Что я сделал здесь неправильно?
Большое спасибо.
Предполагаю, вы используете UUID? Измените CHAR(36)
на CHAR(36) CHARACTER SET ascii
. Лучше было бы упаковать их в BINARY (16). (См. Http://mysql.rjweb.org/doc.php/uuid.) Это уменьшает размер от 108 до 36 до 16.
Вы говорите, что использует filesort и т.д., Но использует ли PRIMARY
? Предоставьте EXPLAIN SELECT...
Но, чтобы еще быстрее ускорить работу, подумайте о создании и обслуживании "Сводной таблицы (таблиц)". (См. Http://mysql.rjweb.org/doc.php/summarytables.) Если у вас была одна строка в сводной таблице за комбо (time, placement_id, line_id), GROUP BY
и SUM
могли быть удалены. (Если вы суммируете по часам, вам все равно нужны.)
Если вы будете изучать документацию MySQL для оптимизации запросов агрегирования, вы обнаружите, что существует два метода оптимизации запроса GROUP BY
, а именно: рыхлые и плотные проверки индексов. Тем не менее, одна оговорка для любого из этих сканов заключается в том, что единственными агрегатными функциями, используемыми в списке выбора, являются MIN
или MAX
. Поскольку вы выбираете SUM
, эти оптимизации недоступны.
Имеет смысл использовать индекс, который может принести пользу вашему WHERE
, поскольку это может позволить нам отбросить записи из набора результатов на ранней стадии в плане запроса. Однако для вычисления суммы для каждой группы MySQL должен касаться каждой записи в оставшейся таблице. Нет никакого способа обойти это, чтобы получить сумму, поэтому не имеет никакого значения, как мы обращаемся ко всем этим записям.
USE INDEX(table_test_IDX)
. Время запроса быстрее в 2 раза, чем обычно.