MySQL查询选择性能和两个日期范围在一个选择

时间:2015-09-08 07:07:31

标签: mysql sql

我有一张桌子可以存储这样的商店人数:

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:enter image description here(id_station与id_store相同)

祝你好运

1 个答案:

答案 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进行报告,那为什么不包括它……那仍然是一天的总数……不重要,只是查询。