У меня есть отчет, который извлекает информацию из сводной таблицы и в идеале извлекает данные из двух периодов одновременно, текущего периода и предыдущего периода. Моя таблица структурирована таким образом:
report_table
item_id INT(11)
amount Decimal(8,2)
day DATE
Первичный ключ - item_id, день. Эта таблица в настоящее время содержит 37 тысяч записей с 92 различными предметами и 1200 разными днями. Я использую Mysql 5.1.
Вот мой выбор:
SELECT r.day, sum(r.amount)/(count(distinct r.item_id)*count(r.day)) AS `current_avg_day`,
sum(r2.amount)/(count(distinct r2.item_id)*count(r2.day)) AS `previous_avg_day`
FROM `client_location_item` AS `cla`
INNER JOIN `client_location` AS `cl`
INNER JOIN `report_item_day` AS `r`
INNER JOIN `report_item_day` AS `r2`
WHERE (r.item_id = cla.item_id)
AND (cla.location_id = cl.location_id)
AND (r.day between from_unixtime(1293840000) and from_unixtime(1296518399))
AND (r2.day between from_unixtime(1291161600) and from_unixtime(1293839999))
AND (cl.location_code = 'LOCATION')
group by month(r.day);
В настоящее время этот запрос занимает 2,2 секунды в моей среде. План объяснения:
'1', 'SIMPLE', 'cl', 'ALL', 'PRIMARY', NULL, NULL, NULL, '33', 'Using where; Using temporary; Using filesort'
'1', 'SIMPLE', 'cla', 'ref', 'PRIMARY,location_id,location_id_idxfk', 'location_id', '4', 'cl.location_id', '1', 'Using index'
'1', 'SIMPLE', 'r', 'ref', 'PRIMARY', 'PRIMARY', '4', cla.asset_id', '211', 'Using where'
'1', 'SIMPLE', 'r2', 'ALL', NULL, NULL, NULL, NULL, '37602', 'Using where; Using join buffer'
Если я добавлю индекс в столбец «день», вместо того, чтобы мой запрос выполнялся быстрее, он выполняется за 2,4 секунды. План объяснения для запроса на тот момент:
'1', 'SIMPLE', 'r2', 'range', 'report_day_day_idx', 'report_day_day_idx', '3', NULL, '1092', 'Using where; Using temporary; Using filesort'
'1', 'SIMPLE', 'r', 'range', 'PRIMARY,report_day_day_idx', 'report_day_day_idx', '3', NULL, '1180', 'Using where; Using join buffer'
'1', 'SIMPLE', 'cla', 'eq_ref', 'PRIMARY,location_id,location_id_idxfk', 'PRIMARY', '4', 'r.asset_id', '1', 'Using where'
'1', 'SIMPLE', 'cl', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', cla.location_id', '1', 'Using where'
Согласно документации MySQL, наиболее эффективная группа по исполнению - это когда есть индекс для извлечения столбцов группировки. Но в нем также говорится, что единственными функциями, которые действительно могут использовать индексы, являются min () и max (). У кого-нибудь есть идеи, что я могу сделать для дальнейшей оптимизации моего запроса? Или почему моя «проиндексированная» версия работает медленнее, несмотря на то, что в целом она содержит меньше строк, чем неиндексированная версия?
Создать таблицу:
CREATE TABLE `report_item_day` (
`item_id` int(11) NOT NULL,
`amount` decimal(8,2) DEFAULT NULL,
`day` date NOT NULL,
PRIMARY KEY (`item_id`,`day`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
Конечно, другой вариант, который у меня есть, - это сделать вызовы по 2 дБ, по одному на каждый период времени. Если я это сделаю, сразу запрос для каждого падает до 0,031 с. Тем не менее, я чувствую, что должен быть способ оптимизировать этот запрос для достижения сопоставимых результатов.