У меня есть таблица, в которой хранится список URI, подлежащих обходу. Это 'crawl_index' схема таблицы является:MySQL - проблемы с производительностью с «Group by»
CREATE TABLE `crawl_index` (
`id` INTEGER(10) NOT NULL AUTO_INCREMENT,
`uri` TEXT NOT NULL,
`domain` VARCHAR(255) NOT NULL,
`last_crawled_date` INTEGER(10) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
INDEX `crawler_INDEX_1` (`domain`),
INDEX `crawler_INDEX_2` (`last_crawled_date`)
) ENGINE=InnoDB;
Некоторые подробности об этой таблице:
- он содержит около 1 млн строк.
- Почти 60% строк имеют значение «last_crawled_date» равное 0 (быстрее извлекать URI с обходной страницы, чем при обходе страницы).
- Поле "id" никогда не используется. Я добавляю только к схеме, чтобы иметь явную primary_key, поскольку я не мог создать первичный ключ в поле «uri», так как это несвязанный текст.
То, что я хочу сделать, это выбрать N строк со следующими ограничениями:
- URI, не должен был уже пополз в последние 2 дня
- Я не хочу, чтобы все вернулись URI из одного домена, чтобы избежать слишком большого количества запросов в одном домене одновременно.
На данный момент, я попробовал этот запрос:
select * from crawl_index where last_crawled_date <= 1373273029 group by domain limit 3;
Это дает мне такой результат:
+--------+------------------------+--------------+-------------------+
| id | uri | domain | last_crawled_date |
+--------+------------------------+--------------+-------------------+
| 60239 | http://example1.com/1 | example1.com | 0 |
| 239 | http://example2.com/1 | example2.com | 0 |
| 120239 | http://example3.com/1 | example3.com | 0 |
+--------+------------------------+--------------+-------------------+
3 rows in set (1,23 sec)
Это работает, но это довольно медленно по сравнению с тем же запросом без оператор "group by". Когда я бегу explain
на этот запрос, я получил это:
+----+-------------+-------------+-------+-----------------+-----------------+---------+------+-------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+-------+-----------------+-----------------+---------+------+------+------------------------+
| 1 | SIMPLE | crawl_index | range | crawler_INDEX_1 | crawler_INDEX_2 | 4 | NULL | 71588 | Using index condition |
| | | | | crawler_INDEX_2 | | | | | Using temporary |
| | | | | | | | | | Using filesort |
+----+-------------+-------------+-------+-----------------+-----------------+---------+------+-------+-----------------------+
Я уже:
- создания индексов LAST_CRAWLED_DATE и доменных полей
- использует целое число, чтобы сохранить мой LAST_CRAWLED_DATE избежать даты-времени сравнения
- предварительно вычисляет max_date в моем PHP-коде, чтобы избежать запроса mysql сделать это для меня.
Какую идею я могу улучшить?
Использование 'ENUM' не представляется возможным, так как оно будет обновлять схему каждый раз, когда мы хотим добавить новый домен в обход. Увеличение предела памяти - хорошая идея.Я проверю его и расскажу, есть ли у него повышенные показатели. Но пока я пытаюсь понять, почему вслух объяснение говорит мне, что он больше не использует «filesort», «временный» и «индекс», а просто «где» ... Только изменение, которое я сделал, это добавить несколько сотен тысяч урисов в моем столе, чтобы имитировать ограничения производства. Время отклика остается в основном одинаковым: от 1,5 до 2 секунд. Странный... – Remi