我制作了一个抓取脚本,用于将某些网站的信息下载到数据库中,该数据库用于进一步监控历史列表信息及其总计数。
这是表格的结构:
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
将所有数据存储在一个表中的原因是什么?当前脚本设置为继续将信息抓取到同一个表本身。我不能丢失任何数据,我也应该让报告更快地进行查询。
在某些论坛中,我发现表格大小在这种情况下不是问题,适当的分区会有所帮助。由于我对数据感到担忧,我对制作实验感到困惑和担心。
由于该表应该在以后有更多记录,因此表的分区可以帮助我。我只是从参考文档中获得了分区的想法,我对如何实现它感到困惑?
任何建议或建议都非常有意义。如有必要,我还可以提供任何支持信息。
答案 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_date
和type
列上为您的数据库表创建索引,这将有助于快速执行您的查询