2016-10-14 3 views
1

죄송합니다. 제목에 대해 더 구체적으로 설명 드릴 수 없습니다. 긴 MySql 쿼리에서 인덱스 최적화

그래서 나는이 쿼리 가지고 :

CREATE TABLE RecordPoints AS (
SELECT competitionId, personId, personCountryId, eventId, year, date, 
if(regionalAverageRecord = 'WR', 
(SELECT COUNT(DISTINCT personId) FROM ResultDates rd 
WHERE rd.eventId=rd2.eventId AND rd.date <= rd2.date AND rd.average > 0), 0) wrAveragePoints, 
if(regionalSingleRecord = 'WR', 
(SELECT COUNT(DISTINCT personId) FROM ResultDates rd 
WHERE rd.eventId=rd2.eventId AND rd.date <= rd2.date), 0) wrSinglePoints, 
if(NOT regionalAverageRecord in('WR', 'NR'), 
(SELECT COUNT(DISTINCT personId) FROM ResultDates rd 
WHERE rd.eventId=rd2.eventId AND rd.date <= rd2.date AND average > 0 AND rd.personCountryId in 
(SELECT Countries.id FROM Countries JOIN Continents on Countries.continentId=Continents.id where recordName = rd2.regionalAverageRecord)), 0) crAveragePoints, 
if(NOT regionalAverageRecord in('WR', 'NR'), 
(SELECT COUNT(DISTINCT personId) FROM ResultDates rd 
WHERE rd.eventId=rd2.eventId AND rd.date <= rd2.date AND rd.personCountryId in 
(SELECT Countries.id FROM Countries JOIN Continents on Countries.continentId=Continents.id where recordName = rd2.regionalSingleRecord)), 0) crSinglePoints, 
if(regionalAverageRecord = 'NR', 
(SELECT COUNT(DISTINCT personId) FROM ResultDates rd 
WHERE rd.eventId=rd2.eventId AND rd.date <= rd2.date AND rd.personCountryId=rd2.personCountryId AND rd.average > 0), 0) nrAveragePoints, 
if(regionalSingleRecord = 'NR', 
(SELECT COUNT(DISTINCT personId) FROM ResultDates rd 
WHERE rd.eventId=rd2.eventId AND rd.date <= rd2.date AND rd.personCountryId=rd2.personCountryId), 0) nrSinglePoints 
FROM ResultDates rd2 WHERE (NOT regionalAverageRecord='' OR NOT regionalSingleRecord = '')); 

을 그리고 그것은 완료 9시간했다. 그것을 분해하기 위해, 필자는 열 6 개가 전체 하위 쿼리인데, 여기에서 date와 몇 가지를 기준으로 한 일이 발생하기 전에 동일한 테이블에 personId가 몇 번 나타나는지 계산합니다. 다른 열. CREATE INDEX date ON ResultDates (date)을 사용하여 날짜에 색인을 생성하는 것은 생각보다 조금 빨라졌지만 여전히 괴로운 시간이 걸립니다.

+------------+-----------------+---------------+---------+---------+-----+---------+----------------------+-----------------------+-------+-----+------+------------+ 
| personId | personCountryId | competitionId | eventId | roundId | pos | average | regionalSingleRecord | regionalAverageRecord | month | day | year | date  | 
+------------+-----------------+---------------+---------+---------+-----+---------+----------------------+-----------------------+-------+-----+------+------------+ 
| 1982THAI01 | USA    | WC1982  | 333  | f  | 1 |  0 | WR     |      |  6 | 5 | 1982 | 1982-06-05 | 
+------------+-----------------+---------------+---------+---------+-----+---------+----------------------+-----------------------+-------+-----+------+------------+ 

같은 ResultDates 찾는

행 regionalSingleRecord 및 regionalAverageRecord이 "RecordNames"의가 될 수 있습니다 : WR를, NR, 아무것도 대부분의 시간, 또는 AFR, ASR, ER, NAR, OCR , SAR을 사용하여 그 recordNames가 연결되어있는 대륙을 기반으로 한 국가를 찾습니다.

이 레코드 이름을 대륙에 연결하고 대륙 id를 countryIds에 연결하는 색인을 만들었지 만 속도가 어느 정도 향상되었는지는 알 수 없습니다.

그것을 EXPLAIN 실행하면이 나에게 반환

+----+--------------------+------------+------------+------+-------------------+--------------+---------+----------------------------------+--------+----------+---------------------------------------------------------------+ 
| id | select_type  | table  | partitions | type | possible_keys  | key   | key_len | ref        | rows | filtered | Extra               | 
+----+--------------------+------------+------------+------+-------------------+--------------+---------+----------------------------------+--------+----------+---------------------------------------------------------------+ 
| 1 | PRIMARY   | rd2  | NULL  | ref | idx_personId  | idx_personId | 32  | const       | 567 | 99.00 | Using where             | 
| 9 | DEPENDENT SUBQUERY | rd   | NULL  | ALL | date,idx_personId | NULL   | NULL | NULL        | 992294 |  0.33 | Range checked for each record (index map: 0x3)    | 
| 8 | DEPENDENT SUBQUERY | rd   | NULL  | ALL | date,idx_personId | NULL   | NULL | NULL        | 992294 |  0.11 | Range checked for each record (index map: 0x3)    | 
| 6 | DEPENDENT SUBQUERY | Continents | NULL  | ref | P_id,recordIndex | recordIndex | 9  | cubing.rd2.regionalSingleRecord |  1 | 100.00 | Using index; Start temporary         | 
| 6 | DEPENDENT SUBQUERY | Countries | NULL  | ALL | NULL    | NULL   | NULL | NULL        | 203 | 10.00 | Using where; Using join buffer (Block Nested Loop)   | 
| 6 | DEPENDENT SUBQUERY | rd   | NULL  | ALL | date    | NULL   | NULL | NULL        | 992294 |  0.33 | Range checked for each record (index map: 0x1); End temporary | 
| 4 | DEPENDENT SUBQUERY | Continents | NULL  | ref | P_id,recordIndex | recordIndex | 9  | cubing.rd2.regionalAverageRecord |  1 | 100.00 | Using index; Start temporary         | 
| 4 | DEPENDENT SUBQUERY | Countries | NULL  | ALL | NULL    | NULL   | NULL | NULL        | 203 | 10.00 | Using where; Using join buffer (Block Nested Loop)   | 
| 4 | DEPENDENT SUBQUERY | rd   | NULL  | ALL | date    | NULL   | NULL | NULL        | 992294 |  0.11 | Range checked for each record (index map: 0x1); End temporary | 
| 3 | DEPENDENT SUBQUERY | rd   | NULL  | ALL | date,idx_personId | NULL   | NULL | NULL        | 992294 |  3.33 | Range checked for each record (index map: 0x3)    | 
| 2 | DEPENDENT SUBQUERY | rd   | NULL  | ALL | date,idx_personId | NULL   | NULL | NULL        | 992294 |  1.11 | Range checked for each record (index map: 0x3)    | 
+----+--------------------+------------+------------+------+-------------------+--------------+---------+----------------------------------+--------+----------+---------------------------------------------------------------+ 

나는 그것의 속도를 개선하는 방법에 대한 몇 가지 인터넷 검색을 해왔습니다. 내 인터넷 검색을 기반으로, 나는 그것이 좋지 않다는 것을 안다. 특히 초기 테이블에있는 992294 행을보고 있습니다.

내 문제는이 모든 것을 더 빠르게 최적화하는 방법을 모르겠다는 것입니다. 신중하게 만들어진 인덱스는 속도를 향상시킬 수 있으므로 어떤 인덱스를 사용할 수 있는지 궁금합니다.

답변

0

select 절의 하위 쿼리는 매우 많은 비용이 듭니다. 상관 관계가있는 하위 쿼리는 일반적으로 성능이 좋지 않으며 대체로 더 나은 대안을 가지고 있습니다.

나는 철저한 답을 줄 시간이 없지만 질의를 감추는 일반적인 감명은 아마도 당신을 메인 쿼리에서 한번, 스스로 결과를 내고자 할 수있다. SELECT 절에서 조건부 집계를 사용하십시오. 이런 식으로 뭔가 ...

SELECT rd.competitionId, rd.personId, rd.personCountryId, rd.eventId 
    , rd.year, rd.date 
    , COUNT(DISTINCT IF(rd.regionalAverageRecord = 'WR' AND rdPrev.average > 0, rdPrev.person_id, NULL) AS wrAveragePoints 
    , COUNT(DISTINCT IF(regionalSingleRecord = 'WR', rdPrev.person_id, NULL) AS wrSinglePoints 
    , [etc....] 
FROM ResultDates AS rd 
LEFT JOIN ResultDates AS rdPrev 
    ON rd.eventId=rdPrev.eventId 
    AND rdPrev.date <= rd.date 
WHERE (NOT rd.regionalAverageRecord='' OR NOT rd.regionalSingleRecord = '') 
; 

것은 편집 : 서브 질의 /를 CountriesContinents 테이블을 포함하는 필드는, 당신은 단지 해당 테이블에 LEFT JOIN뿐만 아니라 수 있습니다 방법과 유사한 방식으로 결합 된 값을 사용 wrAveragePoints 계산에 rdPrev.average이 사용되었다고 시연했습니다.

참고 : COUNT() 및 기타 대부분의 집계 함수는 NULL 값을 무시합니다.