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

时间:2010-01-25 14:30:13

标签: sql mysql nested-query

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

假设我有一个巨大的工作表(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,我想知道这种方法我是否错了。我应该以不同方式重写我的查询吗?怎么样?

2 个答案:

答案 0 :(得分:2)

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

只需在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来删除重复项,并且会慢得多。

答案 1 :(得分:2)

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

为什么使用LEFT JOIN代替JOIN加入tools