使用子查询在MYSQL中查询优化?

时间:2015-11-12 00:31:50

标签: mysql optimization subquery query-optimization

在作业中,我收到了一个查询并要求对其进行优化。 查询是:

SELECT
    C.yearID as year,
    name as teamName,
    C.lgID as league,
    D.cnt as totalBatters,
    C.cnt as aboveAverageBatters
FROM
    (SELECT 
        count(masterID) as cnt, A.yearID, A.teamID, A.lgID
    FROM
        (select 
        masterID,
            teamID,
            yearID,
            lgID,
            sum(AB),
            sum(H),
            sum(H) / sum(AB) as avg
    FROM
        batting
    GROUP BY teamID , yearID , lgID , masterID) B, (select 
        teamID,
            yearID,
            lgID,
            sum(AB),
            sum(H),
            sum(H) / sum(AB) as avg
    FROM
        batting
    WHERE ab is not null
    GROUP BY teamID , yearID , lgID) A
    WHERE
        A.avg >= B.avg AND A.teamID = B.teamID
            AND A.yearID = B.yearID
            AND A.lgID = B.lgID
    GROUP BY teamID , yearID , lgID) C,
    (SELECT 
        count(masterID) as cnt, yearID, teamID, lgID
    FROM
        batting
    WHERE ab is not null
    GROUP BY yearID , teamID , lgID) D, 
    teams
WHERE
    C.cnt / D.cnt >= 0.75
        AND C.yearID = D.yearID
        AND C.teamID = D.teamID
        AND C.lgID = D.lgID
        AND teams.yearID = C.yearID
        AND teams.lgID = C.lgID
        AND teams.teamID = C.teamID

我想知道可以做些什么来优化它?我是这个概念的新手,对如何进行有点困惑。一般来说,如何优化其中包含select语句的子查询?

1 个答案:

答案 0 :(得分:4)

  

一般情况下,如何优化其中包含select语句的子查询?

以下是一些让您入门的建议。我将尊重这是一项任务的事实,最后,您将通过自己完成并一路学习来更好地理解SQL查询。

我希望该作业包含一种可以导入MySQL的数据集,以便您可以在进行更改时运行查询,并注意对执行计划和整体性能的影响。

别名

在考虑优化之前,或许您可以了解如何使代码更易于阅读,理解和维护。子查询的行为方式类似于常规表,因此,应该为它们提供别名/名称,这些别名/名称对于数据集的含义是有意义的

他们是别名BACD,看起来几乎是故意命名为混淆,但实际上你会惊讶于你经常看到不好的命名现实生活中的/别名,生产SQL代码。

尝试查看(如果可以,运行)每个子查询,查看字段及其含义,然后用一个好名称替换别名,并相应地更新不同列中的引用。这将优化查询以获得更好的清晰度,并最终实现可维护性。

JOINŠ

希望在此次分配时,已经涵盖了各种类型的JOIN操作。如果没有,here is a good summary from a StackOverflow answer。还有大量其他资源涵盖JOIN的来龙去脉,包括TechOnTheNet上的好帖子。

让我们删除子查询并查看整个查询的结构。我通过评论替换了逻辑,使其更加明显:

SELECT
--columns
FROM 
(
    SELECT  
    --columns
    FROM 
    (
        select 
        --columns
        FROM batting
    ) B, 
    (
        select 
        --columns
    ) A
    WHERE
    --some comparisons of averages
) C,
(
    SELECT 
     --columns
    FROM batting
) D, 
teams
WHERE
    --a filter based on a calculation
    C.cnt / D.cnt >= 0.75
    --um... what is all this stuff doing down here?
    --shouldn't those be in a JOIN?
        AND C.yearID = D.yearID
        AND C.teamID = D.teamID
        AND C.lgID = D.lgID
        AND teams.yearID = C.yearID
        AND teams.lgID = C.lgID
        AND teams.teamID = C.teamID

您是否注意到任何奇怪的东西或任何看起来很奇怪的东西?如果您之前没有看过,我强烈建议您按Bad habits to kick : using old-style JOINs阅读Aaron Bertrand

阅读之后,再次查看此查询的框架,使用现代JOIN可以做出的改进应该脱颖而出。这将使查询在清晰度和可维护性方面更加优化。

关键字案例

的一致性

通过使用关键字的一致大写,您可以使其更具可读性的另一种方式。事实上,使用CAPITAL CASEsmall case约为50/50。对于一个脚本来说,这看起来似乎微不足道,但是当这种不一致性遍布整个代码库时,对于必须在其中进行开发并维护它的下一个人来说,它会变得非常恼火。

性能

所以,到目前为止,如果您已经应用了所有内容,那么代码应该更容易解密。就表现而言,有两件事对我来说是有害的。有很多聚合,因此有很多GROUP BY个。

首先查看每个子查询,并在每个聚合中查看。查看在整个查询的上下文中如何使用每个字段。看看你可以删除哪些,也许编写查询的人最初认为他们需要,但最终没有使用并忘记删除它们。

GROUP BY字段尝试相同的策略,这些字段是您没有聚合的每个字段,包含在具有一个或多个聚合操作的查询中。 GROUP BY可能会变得相当昂贵,而且导出的子查询也有GROUP BY这一事实更加复杂。

您可以尝试其他一些技巧,这些技巧更先进,可能会在I / O受损时提高执行效率,例如提取一个或多个子查询'结果集到临时表中,这将释放主表上的锁。

这些优化可能并不一定总能提高执行速度本身,但在负载数据库服务器的生产环境中,速度通常不是优化的主要考虑因素,而是#34 ;亮度" (或尽可能减少服务器上的负载占用量)通常比原始速度更有价值,最终使用更多资源。

我希望这有帮助!