У меня проблемы с оптимизацией относительно простого запроса, включающего GROUP BY, ORDER BY и LIMIT. В таблице чуть более 300 000 записей. Вот схема (я добавил несколько дополнительных индексов для экспериментов):
CREATE TABLE `scrape_search_results` (
`id` int(11) NOT NULL auto_increment,
`creative_id` int(11) NOT NULL,
`url_id` int(11) NOT NULL,
`access_date` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `creative_url_index` (`creative_id`,`url_id`),
KEY `access_date_index` (`access_date`),
KEY `access_date_creative_id_index` (`access_date`,`creative_id`),
KEY `creative_id_access_date_index` (`creative_id`,`access_date`),
KEY `test_index` USING HASH (`creative_id`)
) ENGINE=MyISAM AUTO_INCREMENT=4252725 DEFAULT CHARSET=latin1
В таблице один creative_id
может появляться несколько (сотни) раз. Вопрос, на который я пытаюсь ответить, является относительно простым; дай мне первые 20 creative_ids
по заказу access_date
. Вот мой SQL:
SELECT `ScrapeSearchResult`.`creative_id`,
MAX(`ScrapeSearchResult`.`access_date`) AS `latest_access_date`
FROM `scrape_search_results` AS `ScrapeSearchResult`
WHERE 1 = 1
GROUP BY `ScrapeSearchResult`.`creative_id`
ORDER BY `latest_access_date` DESC
LIMIT 20;
Вот результаты выполнения этого запроса, где мы видим, что 20-е место по величине access_date
равно 2010-08-23 11: 03: 25:
+-------------+---------------------+
| creative_id | latest_access_date |
+-------------+---------------------+
| 550 | 2010-08-23 11:07:49 |
| 4568 | 2010-08-23 11:07:49 |
| 552 | 2010-08-23 11:07:49 |
| 2109 | 2010-08-23 11:07:49 |
| 5221 | 2010-08-23 11:07:49 |
| 1544 | 2010-08-23 11:07:49 |
| 1697 | 2010-08-23 11:07:49 |
| 554 | 2010-08-23 11:07:12 |
| 932 | 2010-08-23 11:05:48 |
| 11029 | 2010-08-23 11:05:37 |
| 11854 | 2010-08-23 11:05:27 |
| 11856 | 2010-08-23 11:05:05 |
| 702 | 2010-08-23 11:03:56 |
| 4319 | 2010-08-23 11:03:56 |
| 7159 | 2010-08-23 11:03:56 |
| 10610 | 2010-08-23 11:03:46 |
| 5540 | 2010-08-23 11:03:46 |
| 1 | 2010-08-23 11:03:46 |
| 11942 | 2010-08-23 11:03:35 |
| 7900 | 2010-08-23 11:03:25 |
+-------------+---------------------+
Если бы я собирался написать этот алгоритм вручную, я бы построил b-дерево, упорядоченное по (access_date
, creative_id
). Я начинаю с MAX(access_date)
и продолжаю ходить по дереву, пока не найду 20 уникальных creative_ids
, которые затем вернусь в том порядке, в котором я их нашел.
Используя этот алгоритм, мне нужно было бы рассмотреть только 94 строки (есть 94 строки, для которых access_date >= 2010-08-23 11:03:25
, что является нашим 20-м по величине access_date
, как показано выше).
Однако MySQL решает использовать creative_url_index
при ответе на этот запрос, чего я не понимаю. При этом учитывается более 10000 строк.
ANALYZE TABLE scrape_search_results;
SELECT ...;
+----+-------------+--------------------+-------+---------------+--------------------+---------+------+-------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+-------+---------------+--------------------+---------+------+-------+---------------------------------+
| 1 | SIMPLE | ScrapeSearchResult | index | NULL | creative_url_index | 8 | NULL | 10687 | Using temporary; Using filesort |
+----+-------------+--------------------+-------+---------------+--------------------+---------+------+-------+---------------------------------+
Моя проблема в том, что я выполняю ORDER BY для производного столбца MAX(access_date)
? Если да, как я могу оптимизировать мой запрос, чтобы он соответствовал моим ожиданиям?