2011-08-17 4 views
1

MySQL (MAMP 내에서 실행)에 큰 테이블이 있고 2800 만 개의 행과 3.1GB의 크기가 있습니다. 다음은 그 구조 여기매우 느린 선택이있는 큰 MySQL 테이블

CREATE TABLE `termusage` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `termid` bigint(20) DEFAULT NULL, 
    `date` datetime DEFAULT NULL, 
    `dest` varchar(255) DEFAULT NULL, 
    `cost_type` tinyint(4) DEFAULT NULL, 
    `cost` decimal(10,3) DEFAULT NULL, 
    `gprsup` bigint(20) DEFAULT NULL, 
    `gprsdown` bigint(20) DEFAULT NULL, 
    `duration` time DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `termid_idx` (`termid`), 
    KEY `date_idx` (`date`), 
    KEY `cost_type_idx` (`cost_type`), 
    CONSTRAINT `termusage_cost_type_cost_type_cost_code` FOREIGN KEY (`cost_type`) REFERENCES `cost_type` (`cost_code`), 
    CONSTRAINT `termusage_termid_terminal_id` FOREIGN KEY (`termid`) REFERENCES `terminal` (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=28680315 DEFAULT CHARSET=latin1 

은 테이블 표시 상태의 출력입니다 :

Name,Engine,Version,Row_format,Rows,Avg_row_length,Data_length,Max_data_length,Index_length,Data_free,Auto_increment,Create_time,Update_time,Check_time,Collation,Checksum,Create_options,Comment  
'termusage', 'InnoDB', '10', 'Compact', '29656469', '87', '2605711360', '0', '2156920832', '545259520', '28680315', '2011-08-16 15:16:08', NULL, NULL, 'latin1_swedish_ci', NULL, '', '' 

임 다음 select 문을 실행하려고 :

select u.id from termusage u 
    where u.date between '2010-11-01' and '2010-12-01' 

이 돌아갑니다 35 분 소요 결과 (약 1400 만 행) - 이것은 MySQL Worksbench를 사용하고 있습니다.

나는 다음과 같은 MySQL의 구성 설정이 있습니다

Variable_name    Value 
bulk_insert_buffer_size 8388608 
innodb_buffer_pool_instances 1 
innodb_buffer_pool_size 3221225472 
innodb_change_buffering all 
innodb_log_buffer_size  8388608 
join_buffer_size    131072 
key_buffer_size   8388608 
myisam_sort_buffer_size 8388608 
net_buffer_length    16384 
preload_buffer_size   32768 
read_buffer_size    131072 
read_rnd_buffer_size  262144 
sort_buffer_size    2097152 
sql_buffer_result    OFF 

는 결국 더 큰 쿼리를 실행하려고 메신저 - 테이블 및 그룹 일부 데이터의 몇 가지를 결합, 모든 변수에 따라 - 고객 ID -

select c.id,u.termid,u.cost_type,count(*) as count,sum(u.cost) as cost,(sum(u.gprsup) + sum(u.gprsdown)) as gprsuse,sum(time_to_sec(u.duration)) as duration 
from customer c 
inner join terminal t 
on (c.id = t.customer) 
inner join termusage u 
on (t.id = u.termid) 
where c.id = 1 and u.date between '2011-03-01' and '2011-04-01' group by c.id,u.termid,u.cost_type 

이것은 최대 8 개의 행을 반환합니다 (8 개의 별도 cost_types가 있기 때문에). 그러나이 쿼리는 termusage 테이블에 계산할 행이 100 만 개가 넘지 않는 곳에 OK로 실행됩니다. termusage 테이블의 행 수가 큽니다. 선택 시간을 줄일 수 있습니까?

데이터는 LOAD DATA 방법을 사용하여 CSV 파일에서 월 단위로 한 번씩 추가되므로 삽입을 위해 너무 조정할 필요가 없습니다.

편집 : 쇼 메인 쿼리에 대해 설명합니다

id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra 
1,SIMPLE,c,const,PRIMARY,PRIMARY,8,const,1,"Using index; Using temporary; Using filesort" 
1,SIMPLE,u,ALL,"termid_idx,date_idx",NULL,NULL,NULL,29656469,"Using where" 
1,SIMPLE,t,eq_ref,"PRIMARY,customer_idx",PRIMARY,8,wlnew.u.termid,1,"Using where" 
+1

show from query. –

답변

3

두 가지 질문을하는 것처럼 보입니다 - 정확합니까?

첫 번째 쿼리가 너무 오래 걸리는 이유는 IO 바인딩 때문일 수 있습니다. 1400 만 레코드를 디스크에서 MySQL 워크 벤치로 전송하는 데 오랜 시간이 걸립니다.

"설명"하면서 두 번째 쿼리를 시도 했습니까? 예, 8 행만 반환됩니다.하지만 SUM 연산은 수백만 개의 레코드 합계 일 수 있습니다.

"고객"테이블과 "터미널"테이블이 적절하게 색인화되어 있다고 가정합니다. termusage의 기본 키에 가입하면 정말 빠릅니다.

+0

첫 번째 쿼리는 테이블의 느린 속도를 보여주기위한 것입니다. 실제로 쿼리를 실행하면 실행되지 않습니다. 마지막 하나 ... 나는 질문에 대한 최종 질의에 대한 쇼 설명을 추가했다. – ManseUK

+0

where 및 group by 절에 사용 된 모든 열의 색인을 생성했습니다 .... – ManseUK

+0

차가움. explain은 쿼리가 termusage 테이블의 인덱스를 사용하지 않고 있음을 보여줍니다. 많은 설명이 ... termid와 date 컬럼 모두에 인덱스를 만들 수 있습니다. –

0
당신은 날짜 where 절의 규제를 제거하는 시도하고 대신 선택에 IF 문을 넣을 수

그 날짜가 이러한 경계 내에있는 경우, 값 때문에 그렇지 않으면 0 값이 리턴됩니다. SUM은 물론 다른 모든 값이 0이되기 때문에이 범위에 속하는 값만 합산합니다.

필요 이상으로 많은 행을 가져 오는 것이 다소 의미있는 일은 없지만 최근에 오라클 DB에서 관찰 한 결과 상당히 개선되었습니다. 물론 그것은 많은 다른 요소들에 의존 할 것이지만 그것은 시험할만한 가치가있을 것입니다.

+0

제안에 감사드립니다 - (Pelshoff의 의견에서) 색인 작성이 완료 되 자마자 select statement가 날짜없이 실행되는 것을 보게됩니다! – ManseUK

+0

Pelshoff가 대답을 삭제했습니다! – ManseUK

+0

예, 잘못되었습니다. 죄송합니다. – Pelshoff

0

테이블을 수개월이나 수개월로 나누는 것도 생각해보십시오. 그래서 termusage_2010, termusage_2011, 또는 이와 비슷한 것을 가지고 있습니다.

아주 좋은 해결책은 아니지만 테이블이 크기 때문에 작은 서버에서 유용 할 수 있습니다.