Оптимизация MySQL Aggregation Query - PullRequest
4 голосов
/ 01 мая 2009

У меня есть очень большая таблица (~ 100 миллионов записей) в MySQL, которая содержит информацию о файлах. Одной из частей информации является дата изменения каждого файла.

Мне нужно написать запрос, который будет подсчитывать количество файлов, которые соответствуют указанным диапазонам дат. Для этого я создал небольшую таблицу, которая задает эти диапазоны (все в днях) и выглядит так:

DateRanges
range_id   range_name   range_start   range_end
1          0-90         0             90
2          91-180       91            180
3          181-365      181           365
4          366-1095     366           1095
5          1096+        1096          999999999

И написал запрос, который выглядит так:

SELECT r.range_name, sum(IF((DATEDIFF(CURDATE(),t.file_last_access) > r.range_start and DATEDIFF(CURDATE(),t.file_last_access) < r.range_end),1,0)) as FileCount
FROM `DateRanges` r, `HugeFileTable` t
GROUP BY r.range_name

Однако, вполне предсказуемо, этот запрос выполняется вечно. Я думаю, это потому, что я прошу MySQL пройти HugeFileTable 5 раз, каждый раз выполняя вычисление DATEDIFF () для каждого файла.

Вместо этого я хочу просмотреть запись HugeFileTable по записи только один раз, и для каждого файла увеличить значение счетчика в соответствующем итоговом числе range_name. Я не могу понять, как это сделать ....

Может кто-нибудь помочь с этим?

Спасибо.

РЕДАКТИРОВАТЬ : версия MySQL: 5.0.45, таблицы MyISAM

EDIT2 : вот описание, которое было запрошено в комментариях

id  select_type  table  type  possible_keys  key  key_len  ref  rows      Extra  
1   SIMPLE       r      ALL   NULL           NULL NULL     NULL 5         Using temporary; Using filesort 
1   SIMPLE       t      ALL   NULL           NULL NULL     NULL 96506321   

Ответы [ 3 ]

4 голосов
/ 02 мая 2009

Сначала создайте индекс для HugeFileTable.file_last_access.

Затем попробуйте следующий запрос:

SELECT r.range_name, COUNT(t.file_last_access) as FileCount
FROM `DateRanges` r
 JOIN `HugeFileTable` t 
 ON (t.file_last_access BETWEEN 
   CURDATE() + INTERVAL r.range_start DAY AND 
   CURDATE() + INTERVAL r.range_end DAY)
GROUP BY r.range_name;

Вот план EXPLAIN, который я получил, когда попробовал этот запрос на MySQL 5.0.75 (отредактирован для краткости):

+-------+-------+------------------+----------------------------------------------+
| table | type  | key              | Extra                                        |
+-------+-------+------------------+----------------------------------------------+
| t     | index | file_last_access | Using index; Using temporary; Using filesort | 
| r     | ALL   | NULL             | Using where                                  | 
+-------+-------+------------------+----------------------------------------------+

Это все еще не будет работать очень хорошо. При использовании GROUP BY для запроса создается временная таблица, которая может быть дорогой. С этим мало что можно сделать.

Но по крайней мере этот запрос исключает декартово произведение, которое вы имели в исходном запросе.


обновление: Вот еще один запрос, который использует коррелированный подзапрос, но я исключил GROUP BY.

SELECT r.range_name,
  (SELECT COUNT(*) 
   FROM `HugeFileTable` t 
   WHERE t.file_last_access BETWEEN 
     CURDATE() - INTERVAL r.range_end DAY AND 
     CURDATE() - INTERVAL r.range_start DAY
  ) as FileCount
FROM `DateRanges` r;

План EXPLAIN не показывает временную таблицу или сортировку файлов (по крайней мере, с тривиальным количеством строк, которые есть в моих тестовых таблицах):

+----+--------------------+-------+-------+------------------+--------------------------+
| id | select_type        | table | type  | key              | Extra                    |
+----+--------------------+-------+-------+------------------+--------------------------+
|  1 | PRIMARY            | r     | ALL   | NULL             |                          | 
|  2 | DEPENDENT SUBQUERY | t     | index | file_last_access | Using where; Using index | 
+----+--------------------+-------+-------+------------------+--------------------------+

Попробуйте этот запрос к вашему набору данных и посмотрите, работает ли он лучше.

1 голос
/ 01 мая 2009

Хорошо, начните с того, что file_last_access является индексом для таблицы HugeFileTable.

Я не уверен, что это возможно \ лучше, но сначала попробуйте вычислить пределы дат (файлы от даты A до даты B ), а затем используйте какой- > = и <=. По крайней мере теоретически это улучшит производительность. </p>

Сравнение будет примерно таким:

 t.file_last_access >= StartDate AND t.file_last_access <= EndDate 
0 голосов
/ 02 мая 2009

Вы можете получить небольшое улучшение, удалив CURDATE () и поместив дату в запрос, так как она будет дважды запускать эту функцию для каждой строки в вашем SQL.

...