2011-02-14 110 views
1

我需要按照从出生日期开始的年数范围进行分组。这是我迄今为止所做的。如果您使用500000条记录运行存储过程,然后查询我写的内容,则会看到大约需要25秒。我该如何改进它?mysql - 按年份范围划分的组

create table people(
id int not null auto_increment primary key, 
`dob` date 
); 

delimiter // 
drop procedure if exists date_random // 
create procedure date_random(in low date,in upp date,in number int) 
begin 
declare i int default 0; 
while i < number do 
    begin 
    insert into people (`dob`) values (low + interval rand()* datediff(upp,low) day ); 
    set i = i + 1; 
    end; 
end while; 
end // 
delimiter ; 

call date_random('1910-01-01',curdate(),500000); 


delimiter // 
create function `age`(dob date) returns int(11) 
no sql 
begin 
return (year(curdate())-year(dob))-(right(curdate(),5)< right(dob,5)); 
end // 

delimiter ; 


explain select sql_no_cache 
concat_ws('-',min(age(dob)),max(age(dob))) as years, 
count(*) as total 
from people 
group by if(age(dob)=0,1,ceil(age(dob)/5)) 

这是输出解释

+----+-------------+--------+-------+---------------+------+---------+------+--------+----------------------------------------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra          | 
+----+-------------+--------+-------+---------------+------+---------+------+--------+----------------------------------------------+ 
| 1 | SIMPLE  | people | index | NULL   | ip | 4  | NULL | 500000 | Using index; Using temporary; Using filesort | 
+----+-------------+--------+-------+---------------+------+---------+------+--------+----------------------------------------------+ 
1 row in set (0.00 sec) 
+0

如果`EXPLAIN`表示它正在进行大量线性扫描,则可以通过索引`dob`列开始。 – Blrfl 2011-02-14 18:11:00

+0

感谢您的回复。我忘了说我已经添加了dob字段的索引。你好,Marc。 – 2011-02-14 18:29:12

回答

1

你的 '年龄' 功能可以更高效。而不是强制mysql将日期转换为字符串,做子串,比较它们,然后将其转换为最终减法的数字,(year(now()) - year(dob)) - (dayofyear(now()) < dayofyear(dob))怎么样 - 保持它的全部数字并消除至少一层转换。

同样,由于它使用本机日期/时间函数,因此它增加了MySQL可以使用dob列上的索引的机会。由于您在查询时从日期字段中动态获取文本值,因此您的当前方法无法用索引处理。