需要加速MySQL子查询

时间:2011-02-18 22:26:23

标签: 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

任何帮助都将不胜感激。

2 个答案:

答案 0 :(得分:0)

您需要在WHERE条件上添加索引。例如,添加包含字段w.Archivedw.Approved的索引。如果没有这样的索引,MySQL必须首先扫描每一行,而不是确切知道它应该使用哪些行。

但是像Scrum Meister所提到的那样,我们需要查看EXPLAIN输出和表定义,以更好地了解瓶颈在哪里以及如何解决它们。

如果你不能在网上有足够的资源来帮助你理解如何创建最佳索引以提高查询速度。此幻灯片演示提供了从何处开始的基本概述:http://www.slideshare.net/manikandakumar/mysql-query-and-index-tuning

答案 1 :(得分:0)

如果您考虑要选择的内容,则可以将此减少为单个子查询。正如您正在使用COUNT,并计算您正在进行分组的内容。您可以通过一次性计算所有内容来执行相同操作,并将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日期类型。如果它不是日期列,那么可能有些错误。铸造没有索引可以使用。

此外,考虑到mySQL使用索引的最简单方法是为所有列创建COMBINED索引,对每个表进行GROUPING或JOINing。

类似于:

  • 网站[WID,已存档,已批准]
  • Website_Block [WBID,WID,BlockEnabled,Archived]
  • Website_Block_Impressions [WBIID,WBID,StatDate]