为啥在具有多个连接的 WHERE 子句中,子查询比文字值执行得更好?

Posted

技术标签:

【中文标题】为啥在具有多个连接的 WHERE 子句中,子查询比文字值执行得更好?【英文标题】:Why would a sub query perform better than a litteral value in a WHERE clause with multiple joins?为什么在具有多个连接的 WHERE 子句中,子查询比文字值执行得更好? 【发布时间】:2016-11-16 23:31:49 【问题描述】:

进行以下查询:

SELECT *
FROM FactALSAppSnapshot AS LB 
     LEFT OUTER JOIN MLALSInfoStage AS LA ON LB.ProcessDate = LA.ProcessDate AND 
                                                   LB.ALSAppID = LA.ALSNumber
     LEFT OUTER JOIN MLMonthlyIncomeStage AS LC ON LB.ProcessDate = LC.ProcessDate AND
                                                        LB.ALSAppID = LC.ALSNumber
     LEFT OUTER JOIN DimBranchCategory AS LI on LB.ALSAppBranchKey = LI.Branch
WHERE LB.ProcessDate=(SELECT TOP 1 LatestProcessDateKey
                      FROM DimDate)

请注意,WHERE 条件是一个标量子查询。运行时是 0:54 导致 367,853 记录。

但是,如果我将 WHERE 子句切换为以下内容:

WHERE LB.ProcessDate=20161116

这以某种方式导致查询运行时跳转到 57:33 仍然导致 367,853 记录。幕后发生了什么会导致运行时的巨大飞跃?我本来希望子查询版本需要更长的时间,而不是文字整数值。

别名为 LI 的表(列表中的最后一个连接)似乎是唯一未在其键上编制索引的表,并且如果我删除该表,似乎允许查询执行更接近第一个查询作为连接并使用整数值而不是子查询。

SQL Server 11

【问题讨论】:

这很奇怪。 SELECT TOP 1 LatestProcessDateKey FROM DimDate 返回什么? LB.ProcessDate 的类型是什么,是否已编入索引? EXPLAIN 说什么?这是一个积极使用的生产数据库吗?如果是这样,您可能只是在等待锁定。 如果你使用Declare @d date = convert(date, 20161116); ... WHERE LB.ProcessDate=@d会怎样 @Schwern 这个小子查询返回我作为整数插入的值(今天截至 2016 年 11 月 16 日)。 ProcessDate 是将 YYYYMMDD 日期表示为 int。我必须在早上抓住EXPLAIN msgs。它在技术上被用作生产服务器,只是在有限的容量下使用。 ProcessDate 是组合键的一部分,所以我假设它已编入索引。 【参考方案1】:

您问题的真正答案在于查询的执行计划。您可以在 SSMS 中查看实际计划。

没有计划,剩下的就是猜测。但是,根据我的经验,改变的是联接的处理方式。根据我的经验,当查询切换到嵌套循环连接时,查询速度会大大降低。这是优化器的心血来潮——当有一个常数时——认为这是运行查询的最佳方式。

我不确定为什么会这样。也许FactALSAppSnapshot(ProcessDate, ALSAppID, ALSAppBranchKey) 上的索引会加快这两个版本的查询。

【讨论】:

以上是关于为啥在具有多个连接的 WHERE 子句中,子查询比文字值执行得更好?的主要内容,如果未能解决你的问题,请参考以下文章

具有多个带有 AND 类型逻辑连接的 where IN 子句的配置单元查询

在 from 子句 *and* where 子句中添加连接条件使查询更快。为啥?

使用子查询添加具有不同 where 子句的列

与查询具有相同 WHERE 子句的子查询

如何正确索引在具有多个连接的查询中使用的表

子查询或连接条件中的where子句之间的区别