改进缓慢的MySQL选择查询或改进数据库结构?

时间:2013-08-03 22:09:47

标签: mysql select relational-database

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

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

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

    • 表名:needsCrawling
    • 列:pageId(页面的FK)
    • 尺寸:最多50K
  3. 抓取工具任务表,其中包含certin抓取工具应抓取的一组网页:

    • 表名:crawlerTaskList
    • 列:id(PK),crawlerId(称为抓取工具的表的FK),pageId(页面的FK)
    • 大小:最多1K行(10个爬虫,每个爬虫在其中的任务列表中不超过100页)
  4. 这背后的想法是表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帖子的人!

3 个答案:

答案 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)

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

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