我有一张桌子可以存储这样的商店人数:
id primary int
id_store int
date date
time_begin time
time_end time
girl int
boy int
man int
deleted int
KEY id_store
KEY date
KEY time_begin
数据:
id store date time_begin time_end girl boy man deleted
1 10 2015-01-01 09:00:00 09:05:00 5 7 8 0
2 10 2015-01-01 09:05:00 09:10:00 3 2 1 0
3 10 2015-01-01 09:10:00 09:15:00 5 4 7 0
4 10 2015-01-01 09:15:00 09:20:00 5 3 8 0
5 20 2015-01-01 09:00:00 09:05:00 7 8 2 0
6 20 2015-01-01 09:00:00 09:05:00 5 7 8 0
7 20 2015-01-01 09:05:00 09:10:00 3 2 1 0
8 20 2015-01-01 09:10:00 09:15:00 5 4 7 0
9 20 2015-01-01 09:15:00 09:20:00 5 3 8 0
可以有1000个商店,每5分钟将有1条记录为每个商店保存女孩/男孩/男人。该表可包含超过10亿条记录。
我想总结一些商店的日期/时间范围内的所有人口统计,这是我的疑问:
SELECT id_store, SUM(girl) girl ,SUM(boy) boy,SUM(man) man
FROM report_demography
WHERE
date between "2015-08-01" and "2015-08-31"
and time_begin >= "09:00:00" AND time_begin < "22:00:00"
AND deleted = 0 AND FIND_IN_SET(id_store,'10,20,30,40,50')
GROUP BY id_store
运行此查询需要2.51分钟(此表中的总行数为900K)。反正有没有改进这个查询?
还有一件事:我希望在上面的查询中结合上个月的人口统计结果,我使用了union,但似乎它不是最好的解决方案。
这是EXPLAIN SELECT:(id_station与id_store相同)
祝你好运
答案 0 :(得分:0)
尽管使用Store IN(…)似乎有部分答案,但未获得更有效结果的原因是因为索引未优化。有时人们认为索引应该在几个INDIVIDUAL列上,这是不正确的。您想要一个与查询WHERE,GROUP BY,ORDER条件最匹配的索引。
根据您的情况,您希望基于4个部分。首先,您使用WHERE子句,然后使用group by。为了帮助您,请从WHERE子句中的字段开始。因此,在
上创建一个单索引( id_store, deleted, date, time_begin )
阐明位置。
WHERE
id_store IN ( 10, 20, 30, 40, 50 )
AND deleted = 0
AND date >= '2015-08-01'
AND date <= '2015-08-31'
AND time_begin >= '09:00:00'
AND time_begin < '22:00:00'
group by
id_store
现在,要获得上个月的比较,您可以创建自己的交叉表,例如
select
rd.id_store,
sum( case when month( rd.Date ) = 7 then girl else 0 end ) as GirlJuly,
sum( case when month( rd.Date ) = 8 then girl else 0 end ) as GirlAug,
sum( case when month( rd.Date ) = 7 then boy else 0 end ) as BoyJuly,
sum( case when month( rd.Date ) = 8 then boy else 0 end ) as BoyAug,
sum( case when month( rd.Date ) = 7 then man else 0 end ) as ManJuly,
sum( case when month( rd.Date ) = 8 then man else 0 end ) as ManAug
from
report_demography rd
WHERE
rd.id_store IN ( 10, 20, 30, 40, 50 )
AND rd.deleted = 0
-- I expanded the date to TWO months... 7/1 to 8/31
AND rd.date >= '2015-07-01'
AND rd.date <= '2015-08-31'
AND rd.time_begin >= '09:00:00'
AND rd.time_begin < '22:00:00'
group by
rd.id_store
现在,可以用更通用的列名结果(例如LastMonth,PriorMonth(分别用于女孩,男孩,男人))编写,并且也可以使用一种更轻松的方式来处理日期。
最后一个问题,为什么您有时间限制。如果这些是来自商店活动报告的计数,并且有人在例如:8:27进行报告,那为什么不包括它……那仍然是一天的总数……不重要,只是查询。