2013-07-11 45 views
0

我有一個存儲要爬網的URI列表的表。這種 'crawl_index' 表架構是:MySQL - 「由...分組」的性能問題

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; 

這個表的一些細節:

  • 它包含了1M行。
  • 將近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) 

它的工作原理,但與沒有相同的查詢是很慢「小組通過」聲明。當我在該查詢運行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避免日期時間比較
  • 預先計算我的PHP代碼中的max_date,以避免讓mysql爲我做這件事。

我可以改進這個查詢的任何想法?

回答

0

使用的filesort

這就是問題所在。您可能會增加您使用的數據庫引擎的內存限制。

另一種解決方案是:也許您可以在域列上使用ENUM而不是VARCHAR(255)

+0

使用'ENUM'似乎不可能,因爲每次我們想要添加新的域進行爬網時,它都會需要更新模式。增加內存限制是個好主意。我會測試它,並會告訴你它是否增加了性能。但現在,我試圖理解爲什麼突然解釋告訴我,它不再使用「filesort」,「臨時」和「索引」了,而只是「在哪裏」......只有改變我做的是添加一個我桌上有幾十萬個uris來模擬生產約束。響應時間基本相同:1.5到2次之間。奇怪... – Remi

1

嘗試在(last_crawled_date,domain)上創建複合索引並查看解釋計劃。它應該減少執行時間。還要刪除其他索引並進行測試。