MySQL 집계 쿼리 최적화
-
03-07-2019 - |
문제
MySQL에는 파일에 대한 정보가 포함 된 매우 큰 테이블 (~ 100million 레코드)이 있습니다. 정보 중 하나는 각 파일의 수정 날짜입니다.
지정된 날짜 범위에 맞는 파일 수를 계산하는 쿼리를 작성해야합니다. 그렇게하기 위해 나는 이러한 범위를 지정하는 작은 테이블을 만들었고 (모든 날) : 다음과 같이 보입니다.
DateRanges
range_id range_name range_start range_end
1 0-90 0 90
2 91-180 91 180
3 181-365 181 365
4 366-1095 366 1095
5 1096+ 1096 999999999
다음과 같이 보이는 쿼리를 썼습니다.
SELECT r.range_name, sum(IF((DATEDIFF(CURDATE(),t.file_last_access) > r.range_start and DATEDIFF(CURDATE(),t.file_last_access) < r.range_end),1,0)) as FileCount
FROM `DateRanges` r, `HugeFileTable` t
GROUP BY r.range_name
그러나 예상 대로이 쿼리는 영원히 실행됩니다. 나는 그것이 MySQL에 각 파일에서 datediff () 계산을 수행 할 때마다 MySQL에 5 번 거대한 5 번을 겪기 때문이라고 생각합니다.
내가 대신하고 싶은 것은 거대한 필수 레코드를 한 번만 레코드로 만 거리는 것입니다. 각 파일에 대해 적절한 범위 _name 총액에서 카운트를 증가시킵니다. 어떻게하는지 알 수 없습니다 ....
누구든지 이것을 도울 수 있습니까?
감사.
편집하다: MySQL 버전 : 5.0.45, 테이블은 Myisam입니다
edit2: 다음은 의견에 요청 된 descibe입니다.
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE r ALL NULL NULL NULL NULL 5 Using temporary; Using filesort
1 SIMPLE t ALL NULL NULL NULL NULL 96506321
해결책
먼저 색인을 만듭니다 HugeFileTable.file_last_access
.
그런 다음 다음 쿼리를 시도하십시오.
SELECT r.range_name, COUNT(t.file_last_access) as FileCount
FROM `DateRanges` r
JOIN `HugeFileTable` t
ON (t.file_last_access BETWEEN
CURDATE() + INTERVAL r.range_start DAY AND
CURDATE() + INTERVAL r.range_end DAY)
GROUP BY r.range_name;
여기에 있습니다 EXPLAIN
MySQL 5.0.75 에서이 쿼리를 시도했을 때 얻은 계획 (Brevity를 위해 편집) :
+-------+-------+------------------+----------------------------------------------+
| table | type | key | Extra |
+-------+-------+------------------+----------------------------------------------+
| t | index | file_last_access | Using index; Using temporary; Using filesort |
| r | ALL | NULL | Using where |
+-------+-------+------------------+----------------------------------------------+
여전히 잘 작동하지 않을 것입니다. 사용하여 GROUP BY
, 쿼리는 임시 테이블이 발생하여 비쌀 수 있습니다. 당신이 그것에 대해 할 수있는 일은 많지 않습니다.
그러나 적어도이 쿼리는 원래 쿼리에있는 데카르트 제품을 제거합니다.
업데이트: 다음은 상관 관계 서브 쿼리를 사용하지만 GROUP BY
.
SELECT r.range_name,
(SELECT COUNT(*)
FROM `HugeFileTable` t
WHERE t.file_last_access BETWEEN
CURDATE() - INTERVAL r.range_end DAY AND
CURDATE() - INTERVAL r.range_start DAY
) as FileCount
FROM `DateRanges` r;
그만큼 EXPLAIN
계획은 임시 테이블이나 파일 조트를 보여주지 않습니다 (적어도 테스트 테이블에있는 사소한 행의 행으로) :
+----+--------------------+-------+-------+------------------+--------------------------+
| id | select_type | table | type | key | Extra |
+----+--------------------+-------+-------+------------------+--------------------------+
| 1 | PRIMARY | r | ALL | NULL | |
| 2 | DEPENDENT SUBQUERY | t | index | file_last_access | Using where; Using index |
+----+--------------------+-------+-------+------------------+--------------------------+
데이터 세트 에서이 쿼리를 시도하고 더 나은 성능이 있는지 확인하십시오.
다른 팁
글쎄, 그것을 시작하십시오 file_last_access
이다 인덱스 테이블을 위해 HugeFileTable
.
이것이 가능하는지 확실하지 않지만 날짜 제한을 먼저 계산하려고 노력하십시오 (날짜부터 파일 ㅏ 지금까지 비), 그런 다음> = 및 <=로 일부 쿼리를 사용하십시오. 이론적으로 적어도 성능을 향상시킬 것입니다.
비교는 다음과 같습니다.
t.file_last_access >= StartDate AND t.file_last_access <= EndDate
Curdate ()를 제거하고 SQL에서 각 행에 대해이 기능을 두 번 실행하므로 쿼리에 날짜를두면 약간의 개선을 얻을 수 있습니다.