Итак, у меня есть одна действительно чудовищная таблица MySQL (записи 900 тыс., всего 180 МБ), и я хочу извлечь из записей подгрупп с более высоким date_updated
и рассчитать средневзвешенное значение в каждой группе. Расчет выполняется в течение ~ 15 часов, и у меня есть сильное чувство, что я делает это неправильно.
Во-первых, чудовищный макет таблицы:
-
category
-
element_id
-
date_updated
-
value
-
weight
-
source_prefix
-
source_name
Только ключ находится на element_id
(BTREE, ~ 8k уникальных элементов).
И процесс расчета:
Сделайте хэш для каждой группы и подгруппы.
CREATE TEMPORARY TABLE `temp1` (INDEX ( `ds_hash` ))
SELECT `category`,
`element_id`,
`source_prefix`,
`source_name`,
`date_updated`,
`value`,
`weight`,
MD5(CONCAT(`category`, `element_id`, `source_prefix`, `source_name`)) AS `subcat_hash`,
MD5(CONCAT(`category`, `element_id`, `date_updated`)) AS `cat_hash`
FROM `bigbigtable` WHERE `date_updated` <= '2009-04-28'
Я действительно не понимаю эту суету с хэшами, но она работала быстрее. Темная магия, я полагаю.
Найти максимальную дату для каждой подгруппы
CREATE TEMPORARY TABLE `temp2` (INDEX ( `subcat_hash` ))
SELECT MAX(`date_updated`) AS `maxdate` , `subcat_hash`
FROM `temp1`
GROUP BY `subcat_hash`;
Присоединитесь к temp1 с помощью temp2, чтобы найти средневзвешенные значения для категорий
CREATE TEMPORARY TABLE `valuebycats` (INDEX ( `category` ))
SELECT `temp1`.`element_id`,
`temp1`.`category`,
`temp1`.`source_prefix`,
`temp1`.`source_name`,
`temp1`.`date_updated`,
AVG(`temp1`.`value`) AS `avg_value`,
SUM(`temp1`.`value` * `temp1`.`weight`) / SUM(`weight`) AS `rating`
FROM `temp1` LEFT JOIN `temp2` ON `temp1`.`subcat_hash` = `temp2`.`subcat_hash`
WHERE `temp2`.`subcat_hash` = `temp1`.`subcat_hash`
AND `temp1`.`date_updated` = `temp2`.`maxdate`
GROUP BY `temp1`.`cat_hash`;
(теперь, когда я просмотрел его и записал все это, мне кажется, что я должен использовать INNER JOIN в последнем запросе (чтобы избежать 900k * 900k temp table)).
Тем не менее, существует ли обычный способ?
UPD: некоторое изображение для справки:
удалена мертвая ссылка ImageShack
UPD: EXPLAIN для предлагаемого решения:
+----+-------------+-------+------+---------------+------------+---------+--------------------------------------------------------------------------------------+--------+----------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------+---------------+------------+---------+--------------------------------------------------------------------------------------+--------+----------+----------------------------------------------+
| 1 | SIMPLE | cur | ALL | NULL | NULL | NULL | NULL | 893085 | 100.00 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | next | ref | prefix | prefix | 1074 | bigbigtable.cur.source_prefix,bigbigtable.cur.source_name,bigbigtable.cur.element_id | 1 | 100.00 | Using where |
+----+-------------+-------+------+---------------+------------+---------+--------------------------------------------------------------------------------------+--------+----------+----------------------------------------------+