WHERE 子句中的 SQL 查询子选择优化 (SQL Server)

Posted

技术标签:

【中文标题】WHERE 子句中的 SQL 查询子选择优化 (SQL Server)【英文标题】:SQL Query subselect optimization in WHERE clause (SQL Server) 【发布时间】:2014-02-03 10:30:03 【问题描述】:

我编写了以下 SELECT 语句:

SELECT DISTINCT someColumn1
FROM someTable
WHERE someColumn2 = (SELECT MAX(someColumn2) FROM someTable)
    AND someColumn3 IN ('Value1','Value2','Value3','Value4','Value5')
ORDER BY someColumn1

该表包含大约 1 000 000 条记录。 WHERE 子句将此数字减少到 50 000。(someColumn2 已编入索引)

如果我将 WHERE 子句中的子选择替换为具体值,则查询执行得更快。

那个子选择执行了不止一次?如何在这样的查询中实现只执行一次子查询?

【问题讨论】:

请发布执行计划。 Could be similar to this question. @MartinSmith 是的,这就是我要寻找的东西 【参考方案1】:

我假设您正在谈论 (SELECT MAX 子查询(但您的问题不是很清楚)。

硬编码一个值而不是运行子查询会更快的原因是子查询必须读取至少一些数据库才能获得最大值,这比告诉它 42 慢,或者无论价值是什么。查看您的查询,(someColumn2, some someColumn3) 上的索引会很好: col2 帮助它获得最大值,一旦得到它,它可以继续遍历 Col3 值以找到您想要的值,可能在同一个索引页面上,而不必对每个 Col2 匹配的数据页进行处理:这将节省一些磁盘 IO。

【讨论】:

【参考方案2】:

您的查询完全有可能返回零记录...为什么,您在内部也没有与外部匹配的 where 条件。让我澄清一下。您的内部查询正在寻找 max( somecolumn2 ),并且假设您的最大值 someColumn2 = 123。但是,您的主要标准仅适用于 someColumn3 是值 1-5 之一的那些记录。如果是这种情况,可能是 1-5 的值,最高的 someColumn2 可能是 87,因此永远找不到匹配的 123,更不用说获得第 1 列的值了。

因此,为了更好地限定,请将您的 someColumn3 也移动到内部查询中,并确保您的覆盖索引位于 ( someColumn3, someColumn2, someColumn1 )

SELECT DISTINCT 
      someColumn1
   FROM 
      someTable
        JOIN ( SELECT MAX(someColumn2) JustOne
                 FROM someTable
                WHERE someColumn3 IN ('Value1','Value2','Value3','Value4','Value5')) QualRecs
         on someTable.someColumn2 = QualRecs.JustOne
   WHERE 
      someColumn3 IN ('Value1','Value2','Value3','Value4','Value5')
   ORDER BY 
      someColumn1

评论反馈...

让我澄清一下您的原始查询的问题。假设您有以下数据。

someColumn1  someColumn2   someColumn3
1            1             value1
2            5             value2
3            8             value3
4            12            value5
5            28            value7
6            48            value8

现在,您的原始查询正在获取第 2 列的最大值...在此数据场景中,最大值为 48,但与 someColumn3 中的“value8”相关联。

现在,剩下的查询。您只需要 someColumn2 等于 48 值的不同 ID,但也必须是“值 1-5”。在这种情况下,不会返回任何记录,因为 48 与 value8 相关联并且超出了您的其他条件。

所以我的查询说...最终查询基于值 1-5,因此从中获取最大值,从而返回 #12,然后将返回匹配项以获取不同的 someColumn1 值。

【讨论】:

但我只需要一些记录,其中 someColumn2 = max(someColumn2) 用于整个表,所以我的查询做我想要的,这个查询不完全(尽管它会在大多数情况下给出相同的结果例) @jannagy02,请查看修订版以及您的方法可能会失败的原因...但是,由于您的示例查询模棱两可且没有可理解的有形数据,尚不完全清楚,但情况确实如此。 是的,我第一次看懂你写的。但是在您描述的情况下,此查询必须返回没有记录。我最初的问题不是关于结果的正确性,我没有写我想查询的内容,我的问题是如何在这样的查询中实现只执行一次子查询。 但是如果我从join右侧切掉where子句,我觉得和我原来的结果一样,只执行一次。 @jannagy02,然后就像我在这里一样,对您正在考虑的相同标准使用单独的查询并分组,以便根据要加入的任何结果键完成一次。这样,它会根据需要执行一次,而不是为每个正在处理的实例执行一次,这在查询中非常昂贵。

以上是关于WHERE 子句中的 SQL 查询子选择优化 (SQL Server)的主要内容,如果未能解决你的问题,请参考以下文章

子选择查询是不是基于它之外的 WHERE 子句进行了优化? [关闭]

SQL在where子句中使用子选择中的列

SQL 优化 where 子句中的条件

深入理解CQL中的Where子句

sql面试题_SQl优化技巧_1注意通配符中like的使用,百分号放后面_2避免在where子句中对字段进行函数操作_3在子查询当中,尽量用exists代替in_4where子句中尽量不要使用(代码片

查询优化(MySql/Sql):将函数移出 where 子句