在 MYSQL 中针对带有子查询的查询进行查询优化?
Query optimization in MYSQL for a query with sub queries?
在一次作业中,有人给了我一个查询并要求我对其进行优化。
查询是:
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 语句的子查询?
In General, how to optimize sub queries which have select statements in it?
这里有一些帮助您入门的想法。我会尊重它是一项作业这一事实,最后,您将通过自己完成并一路学习,更好地理解 SQL 查询。
我希望作业包括一种数据集,您可以将其导入 MySQL 以便您可以 运行 在进行更改时进行查询并注意对执行计划的影响和整体表现。
别名
在考虑优化之前,或许您可以看看如何使代码更易于阅读、理解和维护。子查询的行为方式类似于常规表,因此,它们应该被赋予 aliases/names ,这对于数据集 意味着 .
是有意义的
它们的别名是 B
、A
、C
和 D
,它们看起来几乎是故意命名的,以混淆视听,但实际上你会惊讶于你看到它们的频率现实生活中的可怜 naming/aliasing,生产 SQL 代码。
尝试单独查看(如果可以,运行ning)每个子查询,查看字段及其含义,然后用一个好的名称替换别名,并更新相应地不同的列。这将优化查询以获得更好的清晰度,并最终提高可维护性。
JOIN
s
希望在完成此作业时,已经涵盖了各种类型的 JOIN
操作。如果没有,here is a good summary from a Whosebug answer. There is a large number of other resources covering the ins and outs of JOIN
, including a good post on 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 by Aaron Bertrand。
看完之后,再看看这个查询的骨架,你可以通过使用现代 JOIN
做出的改进应该很突出。这将使查询在清晰度和可维护性方面更加优化。
关键字大小写的一致性
另一种提高可读性的方法是使用一致的关键字大小写。实际上,使用 CAPITAL CASE
和 small case
大约是 50/50。对于一个脚本来说这可能看起来微不足道,但是当这种不一致分布在整个代码库中时,对于下一个必须在其中开发和维护它的人来说真的很烦人。
性能
所以,到现在为止,如果您已经应用了所有的东西,代码应该更容易破译了。就性能而言,有两件事对我来说是有害的。有很多聚合,因此有很多 GROUP BY
s.
首先单独查看每个子查询,然后查看每个聚合。查看每个字段在整个查询的上下文中是如何使用的。查看哪些您可以删除,也许编写查询的人最初认为他们需要,但最终没有使用并忘记删除它们。
对 GROUP BY
字段尝试相同的策略,这些字段是您未聚合但包含在具有一个或多个聚合操作的查询中的每个字段。 GROUP BY
可能会变得非常昂贵,而且派生子查询也有 GROUP BY
.
的事实使情况更加复杂。
您可以尝试一些其他技巧,这些技巧更高级并且可以在 I/O 的折衷下提高执行力,例如将一个或多个子查询的结果集提取到临时表中,这将释放锁定主表。
像这样的优化可能不一定总能提高执行 速度 本身,但在数据库服务器处于负载下的生产环境中,速度通常不是优化的主要关注点,但“轻便”(或尽可能小的服务器负载足迹)通常比最终使用更多资源的原始速度更有价值。
希望对您有所帮助!
在一次作业中,有人给了我一个查询并要求我对其进行优化。 查询是:
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 语句的子查询?
In General, how to optimize sub queries which have select statements in it?
这里有一些帮助您入门的想法。我会尊重它是一项作业这一事实,最后,您将通过自己完成并一路学习,更好地理解 SQL 查询。
我希望作业包括一种数据集,您可以将其导入 MySQL 以便您可以 运行 在进行更改时进行查询并注意对执行计划的影响和整体表现。
别名
在考虑优化之前,或许您可以看看如何使代码更易于阅读、理解和维护。子查询的行为方式类似于常规表,因此,它们应该被赋予 aliases/names ,这对于数据集 意味着 .
是有意义的它们的别名是 B
、A
、C
和 D
,它们看起来几乎是故意命名的,以混淆视听,但实际上你会惊讶于你看到它们的频率现实生活中的可怜 naming/aliasing,生产 SQL 代码。
尝试单独查看(如果可以,运行ning)每个子查询,查看字段及其含义,然后用一个好的名称替换别名,并更新相应地不同的列。这将优化查询以获得更好的清晰度,并最终提高可维护性。
JOIN
s
希望在完成此作业时,已经涵盖了各种类型的 JOIN
操作。如果没有,here is a good summary from a Whosebug answer. There is a large number of other resources covering the ins and outs of JOIN
, including a good post on 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 by Aaron Bertrand。
看完之后,再看看这个查询的骨架,你可以通过使用现代 JOIN
做出的改进应该很突出。这将使查询在清晰度和可维护性方面更加优化。
关键字大小写的一致性
另一种提高可读性的方法是使用一致的关键字大小写。实际上,使用 CAPITAL CASE
和 small case
大约是 50/50。对于一个脚本来说这可能看起来微不足道,但是当这种不一致分布在整个代码库中时,对于下一个必须在其中开发和维护它的人来说真的很烦人。
性能
所以,到现在为止,如果您已经应用了所有的东西,代码应该更容易破译了。就性能而言,有两件事对我来说是有害的。有很多聚合,因此有很多 GROUP BY
s.
首先单独查看每个子查询,然后查看每个聚合。查看每个字段在整个查询的上下文中是如何使用的。查看哪些您可以删除,也许编写查询的人最初认为他们需要,但最终没有使用并忘记删除它们。
对 GROUP BY
字段尝试相同的策略,这些字段是您未聚合但包含在具有一个或多个聚合操作的查询中的每个字段。 GROUP BY
可能会变得非常昂贵,而且派生子查询也有 GROUP BY
.
您可以尝试一些其他技巧,这些技巧更高级并且可以在 I/O 的折衷下提高执行力,例如将一个或多个子查询的结果集提取到临时表中,这将释放锁定主表。
像这样的优化可能不一定总能提高执行 速度 本身,但在数据库服务器处于负载下的生产环境中,速度通常不是优化的主要关注点,但“轻便”(或尽可能小的服务器负载足迹)通常比最终使用更多资源的原始速度更有价值。
希望对您有所帮助!