MySQL查询执行需要一个大表的时间?

时间:2014-07-07 05:58:28

标签: php mysql join optimization query-optimization

我制作了一个抓取脚本,用于将某些网站的信息下载到数据库中,该数据库用于进一步监控历史列表信息及其总计数。

这是表格的结构:

    CREATE TABLE IF NOT EXISTS `biz_listing` (
          `id` bigint(11) NOT NULL,
          `lid` bigint(11) NOT NULL,
          `cid` bigint(11) NOT NULL,
          `name` varchar(300) NOT NULL,
          `type` enum('homeservices','restaurants') NOT NULL,
          `location` varchar(300) NOT NULL,
          `businessID` varchar(300) NOT NULL,
          `reviewcount` int(6) NOT NULL,
          `rating` decimal(10,1) NOT NULL,
          `city` varchar(300) NOT NULL,
          `categories` varchar(300) NOT NULL,
          `result_month` varchar(10) NOT NULL,
          `updated_date` date NOT NULL,
          KEY `businessID` (`businessID`),
          KEY `updated_date` (`updated_date`)
        ) ENGINE=MyISAM DEFAULT CHARSET=utf8;

到目前为止,该脚本已经收集了大约350万个结果,但是由于表中的大量记录,脚本在查询执行中花费了大量时间并导致超时问题。我们有一些查询来生成报告在填充的结果上。抓取脚本是实时的并且正在填充结果,但是目前我无法根据聚合函数进行报告。

供参考,以下是用于汇总报告的查询:

SELECT 
COUNT(t.`type`) AS count,
COUNT(t.`businessID`) AS bizcount, 
SUM(t.reviewcount) AS reviewcount,
t.`type`,t.`location` as city 
FROM `biz_listing` t 
INNER JOIN ( SELECT `businessID`,count(*) c 
FROM `biz_listing` 
where 
DATE_FORMAT(`updated_date`, '%m %Y') 
BETWEEN '01 2014' AND '02 2014' 
group by `businessID` HAVING c = 2 ) t2 ON t2.`businessID` = t.`businessID` 
where DATE_FORMAT(t.`updated_date`, '%m %Y')= '01 2014' 
and t.type='homeservices' 
GROUP BY t.location, t.result_month

以上查询用于获取商家信息计数及其审核计数的位置明智报告。此处列表显示2014年1月和2014年2月在数据库中常见的商家汇总报告。

现在,从表 biz_listing 查询执行需要花费很多时间,而且过程通常会失败。

EXPLAIN

enter image description here

将所有数据存储在一个表中的原因是什么?当前脚本设置为继续将信息抓取到同一个表本身。我不能丢失任何数据,我也应该让报告更快地进行查询。

在某些论坛中,我发现表格大小在这种情况下不是问题,适当的分区会有所帮助。由于我对数据感到担忧,我对制作实验感到困惑和担心。

由于该表应该在以后有更多记录,因此表的分区可以帮助我。我只是从参考文档中获得了分区的想法,我对如何实现它感到困惑?

任何建议或建议都非常有意义。如有必要,我还可以提供任何支持信息。

2 个答案:

答案 0 :(得分:2)

首先要删除DATE_FORMAT并检查日期: -

SELECT 
    COUNT(t.`type`) AS count,
    COUNT(t.`businessID`) AS bizcount, 
    SUM(t.reviewcount) AS reviewcount,
    t.`type`,
    t.`location` as city 
FROM `biz_listing` t 
INNER JOIN 
( 
    SELECT `businessID`,count(*) c 
    FROM `biz_listing` 
    WHERE updated_date BETWEEN '2014/01/01' AND '2014/02/28' 
    GROUP BY `businessID` 
    HAVING c = 2 
) t2 ON t2.`businessID` = t.`businessID` 
WHERE updated_date BETWEEN '2014/01/01' AND '2014/02/28' 
AND t.type='homeservices' 
GROUP BY t.location, t.result_month

这方面的缺点是您必须指定该月的最后一天。你可以使用LAST_DAY结束: -

SELECT 
    COUNT(t.`type`) AS count,
    COUNT(t.`businessID`) AS bizcount, 
    SUM(t.reviewcount) AS reviewcount,
    t.`type`,
    t.`location` as city 
FROM `biz_listing` t 
INNER JOIN 
( 
    SELECT `businessID`,count(*) c 
    FROM `biz_listing` 
    WHERE updated_date BETWEEN '2014/01/01' AND LAST_DAY('2014/02/01')
    GROUP BY `businessID` 
    HAVING c = 2 
) t2 ON t2.`businessID` = t.`businessID` 
WHERE updated_date BETWEEN '2014/01/01' AND LAST_DAY('2014/02/01')
AND t.type='homeservices' 
GROUP BY t.location, t.result_month

请注意,因为它在一个常量LAST_DAY上执行,所以每次在查询中执行一次,而不是对它正在检查的每一行执行一次。

您可能希望在表上添加覆盖索引,并在表上添加update_date(即,一个具有两列的索引)。同样添加一个涵盖businessID和update_date的索引。

编辑

再次查看您的查询,看起来您正在寻找一个月的业务ID上的匹配,该月份和下个月都有记录。如果我理解你想要什么,每个企业每个月只能有1条记录(因此你计算它们超过2个月并使用HAVING ... = 2)。

如果这是正确的,那么你可以做多个连接,每个月一个: -

SELECT 
        COUNT(t0.type) AS count,
        COUNT(t0.businessID) AS bizcount, 
        SUM(t0.reviewcount) AS reviewcount,
        t0.type,
        t0.location as city ,
        t0.result_month
FROM biz_listing t0 
INNER JOIN biz_listing t1
ON t0.businessID = t1.businessID
INNER JOIN biz_listing t2
ON t0.businessID = t2.businessID
WHERE t0.updated_date BETWEEN '2014/01/01' AND LAST_DAY('2014/01/01')
AND t1.updated_date BETWEEN '2014/01/01' AND LAST_DAY('2014/01/01')
AND t2.updated_date BETWEEN '2014/02/01' AND LAST_DAY('2014/02/01')
AND t0.type='homeservices' 
GROUP BY t.location, t.type, t.result_month

请注意,如果我误解了并且businessID每月可以有多条记录,那么这将无效。

答案 1 :(得分:1)

请在updated_datetype列上为您的数据库表创建索引,这将有助于快速执行您的查询