在这种情况下如何避免嵌套 SQL 查询?

Posted

技术标签:

【中文标题】在这种情况下如何避免嵌套 SQL 查询?【英文标题】:How to avoid nested SQL query in this case? 【发布时间】:2011-01-09 03:03:43 【问题描述】:

我有一个 SQL 问题,与 this 和 this 问题有关(但不同)。基本上我想知道如何避免嵌套查询。

假设我有一个巨大的工作表 (jobs),由一家公司在其历史上执行。这些作业的特点是年、月、位置和属于作业所用工具的代码。此外,我还有一个工具表 (tools),将工具代码转换为工具描述和有关工具的更多数据。现在他们想要一个网站,他们可以在其中使用下拉框选择年、月、位置和工具,然后将显示匹配的工作。我想仅使用与之前选择的年份、月份和位置匹配的相关工具来填充最后一个下拉列表,因此我编写了以下嵌套查询:

SELECT c.tool_code, t.tool_description
FROM (
 SELECT DISTINCT j.tool_code
 FROM jobs AS j
 WHERE j.year = ....
        AND j.month = ....
 AND j.location = ....
) AS c
LEFT JOIN tools as t
ON c.tool_code = t.tool_code
ORDER BY c.tool_code ASC

我使用了这个嵌套查询,因为它比在整个数据库上执行 JOIN 并从中选择要快得多。它让我的查询时间减少了很多。但正如我最近读到的mysql nested queries should be avoided at all cost,我想知道我在这种方法上是否错了。我应该以不同的方式重写我的查询吗?怎么做?

【问题讨论】:

【参考方案1】:

不,你不应该,你的查询没问题。

只需在jobs (year, month, location, tool_code)tools (tool_code) 上创建一个索引,以便可以使用INDEX FOR GROUP-BY

您提供的文章描述了子查询谓词 (IN (SELECT ...)),而不是嵌套查询 (SELECT FROM (SELECT ...))。

即使有子查询,文章也是错误的:虽然MySQL 无法优化所有子查询,但它可以很好地处理IN (SELECT …) 谓词。

不知道作者为什么选择把DISTINCT放在这里:

SELECT  id, name, price
FROM    widgets
WHERE   id IN
        (
        SELECT  DISTINCT widgetId
        FROM    widgetOrders
        )

以及为什么他们认为这将有助于提高性能,但鉴于 widgetID 已编入索引,MySQL 只会转换此查询:

SELECT  id, name, price
FROM    widgets
WHERE   id IN
        (
        SELECT  widgetId
        FROM    widgetOrders
        )

转为index_subquery

本质上,这就像EXISTS 子句:每个widgets 行将执行一次内部子查询,并添加额外的谓词:

SELECT  NULL
FROM    widgetOrders
WHERE   widgetId = widgets.id

并在widgetOrders 的第一场比赛中停止。

这个查询:

SELECT  DISTINCT w.id,w.name,w.price
FROM    widgets w
INNER JOIN
        widgetOrders o
ON      w.id = o.widgetId

必须使用temporary 来删除重复项,并且速度会慢得多。

【讨论】:

【参考方案2】:

您可以使用GROUP BY 避免子查询,但如果子查询执行得更好,请保留它。

您为什么使用LEFT JOIN 而不是JOIN 加入tools

【讨论】:

因为我还没有设置表之间的外键关系。完成此操作后,我可以切换到 JOIN,但目前仍有可能将具有未知工具代码的作业添加到数据库中。我需要这些工作仍然在选择中弹出。

以上是关于在这种情况下如何避免嵌套 SQL 查询?的主要内容,如果未能解决你的问题,请参考以下文章

SQL:在这种情况下如何按 sql 顺序查询

在这种情况下如何避免死锁?

如何优化 sql 查询以避免在没有 php.ini 或设置时间限制的情况下执行最长时间 [关闭]

在这种特定情况下,如何使用 SQL 仅检索与日期字段的最后一个值相关的记录?

如何避免嵌套三元运算符

如何避免mysql DB的高负载?