2013-07-11 4 views
0

У меня есть таблица, в которой хранится список 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 сделать это для меня.

Какую идею я могу улучшить?

ответ

0

Использование FileSort

Это проблема. Вы можете увеличить ограничение памяти для используемого вами механизма БД.

Другое решение: возможно, вы можете использовать ENUM в столбце домена вместо VARCHAR(255)?

+0

Использование 'ENUM' не представляется возможным, так как оно будет обновлять схему каждый раз, когда мы хотим добавить новый домен в обход. Увеличение предела памяти - хорошая идея.Я проверю его и расскажу, есть ли у него повышенные показатели. Но пока я пытаюсь понять, почему вслух объяснение говорит мне, что он больше не использует «filesort», «временный» и «индекс», а просто «где» ... Только изменение, которое я сделал, это добавить несколько сотен тысяч урисов в моем столе, чтобы имитировать ограничения производства. Время отклика остается в основном одинаковым: от 1,5 до 2 секунд. Странный... – Remi

1

Попробуйте создать составной индекс на (last_crawled_date, domain) и посмотреть план объяснения. Это должно сократить время выполнения. Удалите остальные индексы и проверьте.

Смежные вопросы