2011-02-18 4 views
0

중첩 된 하위 쿼리를 사용하는 MySQL 쿼리가 있습니다.MySQL 하위 쿼리 속도 향상 필요

웹 페이지를 실행하는 데 약 2 초가 걸리므로 속도를 높이기 위해 여러 가지 방법을 시도했습니다.

어떻게이 쿼리의 속도를 높일 수 있습니까? 이미 뷰 및 쿼리 캐싱을 사용해 보았지만 성능상의 이점은 명목상이었습니다.

SELECT w.WID, 
       max(wb.BlockPrice) as highestPrice, 
       min(wb.BlockPrice) as lowestPrice, 
       max(bi.Impressions) as highestImpressions, 
       min(bi.Impressions) as lowestImpressions 
         FROM Website w 
         JOIN Website_Block wb on wb.WID = w.WID 
        JOIN Website_Block_Impressions wbi on wbi.WBID = wb.WBID and wbi.StatDate > DATE_SUB(NOW(),INTERVAL 1 DAY) 
       JOIN (
       SELECT round((Sum(Impressions)/Count(impDate)) * 30) AS Impressions, WID as WIDImpressions 
        FROM (SELECT COUNT(wbi.WBIID) AS Impressions, 
           CAST(wbi.StatDate AS DATE) AS impDate, 
           wbi.WBID, 
           wb.WID 
          FROM Website_Block_Impressions wbi 
          JOIN Website_Block wb ON wb.WBID = wbi.WBID 
          WHERE wb.BlockEnabled = 1 
          AND wb.Archived = 0 
          AND `wbi`.StatDate > DATE_ADD(now(), INTERVAL -wb.BlockDuration DAY) 
          GROUP BY CAST(wbi.StatDate AS DATE), wbi.WBID) AS impressions 
        GROUP BY WBID) as bi 
         WHERE w.Archived = 0 
         AND w.Approved = 1 
         AND bi.WIDImpressions = w.WID 
         AND bi.Impressions between 0 AND 73000 
         GROUP BY w.WID 
      LIMIT 0,10 

어떤 도움을 주시면 감사하겠습니다.

+4

'EXPLAIN' 출력과 테이블 정의를 게시하여 인덱스가 무엇인지 확인하십시오. –

+1

매우 복잡한 쿼리, 때로는 SQL 만 사용하여 향상시킬 수 없으며 응용 프로그램 수준에서 일부 쿼리를 결합하고 하위 수준 쿼리를 캐시하는 데 응용 프로그램 수준을 사용하는 것이 더 좋을 수도 있습니다 – jlmfao

+0

인덱스는 ID로 끝나는 모든 기본 키 필드에 있으며 wbi.StatDate 필드에 –

답변

0

WHERE 조건에 인덱스를 추가하려고합니다. 예를 들어, w.Archivedw.Approved 필드를 포함하는 인덱스를 추가하십시오. 이런 인덱스가 없다면, MySQL은 모든 행을 먼저 스캔해야하며 정확히 어떤 행을 사용해야하는지 알지 못합니다.

그러나 The Scrum Meister가 언급 한 것처럼 병목 현상이 어디에 있는지와 문제를 해결하는 방법에 대해 더 잘 이해하려면 EXPLAIN 출력과 테이블 정의를 확인해야합니다.

네트워크에 리소스가 충분하지 않은 경우 쿼리 속도를 높이기 위해 최적의 인덱스를 만드는 방법을 이해하는 데 도움이 될 것입니다. 이 슬라이드 쇼에서는 시작 위치에 대한 기본적인 개요를 제공합니다 : http://www.slideshare.net/manikandakumar/mysql-query-and-index-tuning

0

선택하려는 항목에 대해 생각하면이 항목을 단일 하위 쿼리로 줄일 수 있습니다. COUNT를 SUMING하고 GROUPING하고있는 것을 COUNTING하고 있습니다. 한 번에 모든 것을 계산하여 동일하게 수행 할 수 있으며 DISTINCT를 계산하면 다른 부분을 계산합니다.

SELECT 
    w.WID, 
    max(wb.BlockPrice) as highestPrice, 
    min(wb.BlockPrice) as lowestPrice, 
    max(bi.Impressions) as highestImpressions, 
    min(bi.Impressions) as lowestImpressions 
FROM 
    Website w 
    JOIN Website_Block wb on wb.WID = w.WID 
    JOIN Website_Block_Impressions wbi on wbi.WBID = wb.WBID and wbi.StatDate > DATE_SUB(NOW(),INTERVAL 1 DAY) 
    JOIN (
     SELECT 
      ROUND((SUM(wbi.WBIID)/COUNT(DISTINCT DATE(wbi.StatDate))) * 30) AS Impressions 
      wb.WID 
     FROM 
      Website_Block_Impressions wbi 
      JOIN Website_Block wb ON wb.WBID = wbi.WBID 
     WHERE 
      wb.BlockEnabled = 1 
      AND wb.Archived = 0 
      AND `wbi`.StatDate > DATE_ADD(now(), INTERVAL -wb.BlockDuration DAY) 
     GROUP BY 
      wbi.WBID 
    ) bi 
WHERE 
    w.Archived = 0 
    AND w.Approved = 1 
    AND bi.WIDImpressions = w.WID 
    AND bi.Impressions between 0 AND 73000 
GROUP BY 
    w.WID 
LIMIT 0,10 

날짜 유형을 CAST 할 필요가 없습니다. 날짜 열이 아니면 뭔가 잘못되었을 것입니다. CASTing meens는 색인을 사용할 수 없습니다.

또한 mySQL이 인덱스를 사용하는 가장 쉬운 방법은 WHERE, GROUPING 또는 JOINing on 각 테이블에 대한 모든 컬럼에 대해 COMBINED 인덱스를 만드는 것입니다.

그래서 뭔가 같은 : [승인 WID, 보관,]

  • 웹 사이트
  • Website_Block [WBID, WID, BlockEnabled, 보관]
  • Website_Block_Impressions [WBIID, WBID, StatDate]
+0

하위 쿼리가 작동하지 않는다면 합계 값은 수백만 개입니다. –

+0

은 datetime을 날짜로 변환하지만 datetime을 날짜로 형식화하기 위해 변경했습니다. 더 낫니? –

+0

@Jonny Shaw : DATE (datetime)을 사용하는 것이 좋습니다. 그 때문에 당신은 mySQL이 그것을 인식하고 그것을 최적화 할 수있는 가장 많은 기회를 갖게 될 것입니다. 서브 쿼리를 실제로 DATE (wbi.datetime)를 사용하도록 변경했습니다. 그것이 값을 바로 잡을 지 모른다. – ontrack