我正在开发一个包含一个模块的hoby项目,该模块可以抓取网页以获取信息。数据库管理不是我最强大的一面,现在我已经达到了需要帮助的程度。我已经设置了10个爬虫,它们在发布后3分钟最快地从表中爬行页面,并且在发布后不迟于60天(这些时间间隔与爬行系统的工作方式有关)。我有三张桌子:
页面内容表,其中包含已爬网页面中的所有信息以及这些页面的一些元数据(如发布从外部源更新的日期)
需要抓取的网页表。此表中的行由外部系统添加,但在爬网程序完成对此表中页面的爬网时将删除。
抓取工具任务表,其中包含certin抓取工具应抓取的一组网页:
这背后的想法是表1(页面)用于获取publishingDates,然后用于存储获取的爬网结果。表号2用于"标记"应该抓取哪些页面,然后删除"标记"在对它们进行爬网之后(仍然必须检查发布日期,因为在满足发布日期条件时,页面可能需要进行爬网,但不是之前)。表3(crawlerTaskList)主要用于防止抓取工具抓取相同的页面。
我最初用于为抓取工具获取网址的查询如下所示:
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秒的时间点,它开始变得不可持续。我试图重新编写查询(例如使用JOIN而不是id IN / id NOT IN)但没有任何改进,所以我迫切需要建议。也许我必须添加一个我不知道的索引或其他奇特的东西。感谢任何花时间阅读所有这些并抱歉LONG帖子的人!
答案 0 :(得分:2)
在早期版本的MySQL in
中,子查询的优化程度特别差。只需将其移动到连接即可提高性能:
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)
上的索引有助于提高效果。
答案 1 :(得分:0)
尝试在EXPLAIN
之前使用select
(或解释扩展),这应该为您提供所需的信息并提供一些线索,在哪里添加索引以加快查询速度。
答案 2 :(得分:-1)
每个现代数据库都会将您的查询优化到极好的程度,因此您可以编写任何您想要的内容,并且数据库会对其进行优化。
所以你基本上有两个选择: 添加索引到您的表或改善您的数据库(我强烈推荐第二个)