0

我有一个存储要抓取的 URI 列表的表。这个'crawl_index'表模式是:

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)

它可以工作,但与没有“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 和 domain 字段上创建索引
  • 使用整数来存储我的 last_crawled_date 以避免日期时间比较
  • 在我的 PHP 代码中预先计算 max_date 以避免让 mysql 为我做这件事。

知道我可以改进这个查询吗?

4

2 回答 2

1

尝试在 (last_crawled_date, domain) 上创建复合索引并查看说明计划。它应该减少执行时间。也删除其他索引并进行测试。

于 2013-07-12T08:56:06.693 回答
0

使用文件排序

这就是问题。您可以增加您使用的数据库引擎的内存限制。

另一个解决方案是:也许您可以ENUM在域列上使用而不是VARCHAR(255)?

于 2013-07-11T08:31:29.607 回答