2011-02-14 5 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

+0

답장을 보내 주셔서 감사합니다. 이미 dob 필드에 인덱스를 추가했다는 것을 잊어 버렸습니다. –

답변

1

귀하의 '나이'기능을 설명합니다. mysql이 날짜를 문자열로 변환하도록 강요하는 대신 하위 문자열을 수행하고이를 비교 한 다음 마지막 뺄셈을 위해 숫자로 변환합니다. (year(now()) - year(dob)) - (dayofyear(now()) < dayofyear(dob))은 숫자를 그대로 유지하고 적어도 하나의 캐스팅 레이어를 제거합니다.

또한 원래의 날짜/시간 함수를 사용하기 때문에 MySQL이 dob 열의 색인을 사용할 수있는 기회가 증가합니다. 쿼리 메서드를 사용하면 날짜 필드에서 텍스트 값을 동적으로 파생하므로 인덱스를 사용하여 현재 메서드를 처리 할 수 ​​없습니다.

+0

안녕하세요. Marc. 답장을 보내 주셔서 감사합니다. 당신의 충고에 따라 새로운 함수 age2를 만들었습니다. 함수 버전으로 내 쿼리를 시도했지만 약 25 초가 걸리는 동일한 시간이 걸립니다. 설명의 출력은 항상 동일합니다. –

+0

다른 옵션은 샷건으로 이동하여 '나이'열을 만드는 것입니다. 사전 계산/색인을위한 테이블 업데이트를 수행 한 다음 비교에 사용하여 시간에 영향을 미치는지 확인하십시오. 유일한 단점은 검색어가 다른 사람의 생일을 넘을 수있는 작은 창이 나타나면 그로 인해 잘못된 데이터가 발생할 가능성이 조금 있습니다. –

+0

네 말이 맞아. 나이 필드를 테이블에 추가하는 경우concat_ws ('-', 최소 (age), 최대 (age))를 연도로 추가하면 에서 그룹으로 카운트 (* 1, ceil (age/5)) 쿼리에 0.5 초가 걸립니다. 그래서 문제는 쿼리 내에서 함수를 호출하는 것이 었습니다. 감사합니다 –