0

我正在开发一个爱好项目,该项目包含一个抓取网页以获取信息的模块。数据库管理不是我最擅长的方面,我现在已经到了需要帮助的地步。我已经设置了 10 个爬虫,它们最快在发布后 3 分钟从表中同时爬取页面,并且不迟于发布后 60 天(这些时间间隔与爬取系统的工作方式有关)。我有的是三张桌子:

  1. 一个页面内容表,其中包含来自已爬取页面的所有信息以及这些页面的一些元数据(例如从外部源更新的发布日期)

    • 表名:pages
    • 列:id (PK)、url、publishingDate、名称、描述、类别...
    • 大小:约 500K 行
  2. 需要抓取的页面表。此表中的行由外部系统添加,但当爬虫完成对该表中页面的爬取时将其删除。

    • 表名:needsCrawling
    • 列:pageId(页面的 FK)
    • 大小:最多50K
  3. 一个爬虫任务表,其中包含 certin 爬虫应该爬取的一组页面:

    • 表名:crawlerTaskList
    • 列:id(PK),crawlerId(称为爬虫的表的FK),pageId(页面的FK)
    • 大小:最多 1K 行(10 个爬虫,每个爬虫的任务列表中永远不会超过 100 页)

这背后的想法是表1(页面)用于获取发布日期,然后用于存储获取的爬取结果。表号 2 用于“标记”哪些页面应该被抓取,然后在它们被抓取后移除“标记”(仍然必须检查发布日期,因为一个页面可能需要抓取,而不是之前,已满足发布日期标准)。表3(crawlerTaskList)主要用于防止爬虫爬取相同的页面。

我最初用来为爬虫获取 url 的查询如下所示:

SELECT id, url
FROM pages
WHERE publishingDate < NOW() - INTERVAL 3 minute
  AND DATE_SUB(CURDATE(), INTERVAL 60 DAY) < publishingDate
  AND id NOT IN (SELECT pageId FROM crawlerTaskList)
  AND id IN (SELECT pageId FROM needsCrawling)
ORDER BY publishingDate

在页表达到大约 300K 之前,它一直运行良好。现在我已经达到了查询大约需要 40 秒并且开始不可持续的地步。我试图重新编写查询(例如,使用 JOINs 而不是 id IN/id NOT IN)但没有任何改进,所以我迫切需要建议。也许我必须添加一个索引或其他我不知道的花哨的东西。感谢任何花时间阅读所有这些内容的人,并对这篇长篇文章感到抱歉!

4

3 回答 3

2

在早期版本的 MySQLin中,带有子查询的优化特别差。只需将其移动到连接即可提高性能:

SELECT id, url
FROM pages join
     (select distinct pageid from needsCrawling) nc
     on pages.id = nc.pageid left outer join
     (select distinct pageid from crawlerTaskList) ctl
     on pages.id = clt.pageid
WHERE publishingDate < NOW() - INTERVAL 3 minute
  AND DATE_SUB(CURDATE(), INTERVAL 60 DAY) < publishingDate
  AND id ctl.pageid is null
ORDER BY publishingDate;

注意:distinct只有在pageid可以在任一表中重复的情况下才会出现。如果您知道它没有重复,则应将其删除。此外,索引needsCrawling(pageid)crawlerTaskList(pageId)将有助于提高性能。

于 2013-08-03T22:15:00.580 回答
0

尝试使用EXPLAIN(或解释扩展)之前select,这应该为您提供所需的信息并提供一些线索,在哪里添加索引以加快查询速度。

于 2013-08-03T22:24:42.437 回答
-1

每个现代数据库都会将您的查询优化到非常好的程度,因此您可以编写几乎任何您想要的内容,并且数据库会对其进行优化。

所以你基本上有两个选择:为你的表添加索引或改进你的数据库(我强烈推荐第二个)

于 2013-08-03T22:16:39.423 回答