0

我有两个需要加入的表,第一个表包含 CustomerNumber 和 IdentificationNumber,以及 IdentificationType。第二个表包含 IdentificationType、EffectiveDate 和 EndDate。

我的查询基本上是这样的:

Select CustomerNumber, IdentificationNumber
From Identification i
Inner Join IdentificationType it On it.IdentificationType = i.IdentificationType
And it.EffectiveDate < @TodaysDate
And (it.EndDate IS NULL Or it.EndDate > @TodaysDate)

我的执行计划显示了对标识类型表的聚集索引扫描,我假设这是因为连接子句中的 OR。

有没有更有效的加入方式,知道 EndDate 字段必须允许 Null 或真正的日期时间值?

4

2 回答 2

2

我知道您说过该EndDate列必须允许NULL,所以仅作记录:最有效的方法是停止使用NULLs 代替表中的“无结束日期” IdentificationType,而是使用9999-12-31. 然后您的查询可以跳过整个OR子句。(我知道这可能需要对应用程序进行一些更改,但出于这个确切原因,我认为这是值得的——而且我已经看到这种“NULL = 开放式”模式使查询变得困难或一次又一次地表现不佳工作和在线 SQL 问题。)

此外,您可能会考虑交换这两个OR条件的顺序——这听起来像是巫术,但我相信我听说有一些特殊情况,在这种特定情况下,当变量首先出现时它可以更好地优化(尽管我可能是错的)。

同时,您会尝试这个并分享与您的解决方案和其他解决方案相比它的性能如何?

SELECT
   CustomerNumber, IdentificationNumber
FROM
   dbo.Identification i
   INNER JOIN dbo.IdentificationType it
      ON it.IdentificationType = i.IdentificationType
WHERE
   it.EffectiveDate < @TodaysDate
   AND it.EndDate IS NULL
UNION ALL
SELECT
   CustomerNumber, IdentificationNumber
FROM
   dbo.Identification i
   INNER JOIN dbo.IdentificationType it
      ON it.IdentificationType = i.IdentificationType
WHERE
   it.EffectiveDate < @TodaysDate
   AND it.EndDate > @TodaysDate
;

通过使用这种精确的策略,我已经从OR子句的糟糕表现中恢复过来。爆炸查询大小/复杂性是很痛苦的,但是与您现在处理的扫描相比,只进行几次搜索的可能性是完全值得的。

您的不等式比较有些可疑:第一个比较应该有一个等号<=。您没有告诉我们日期列 和 的数据类型@TodaysDate,但最佳做法是设计一个系统,使其不会因任何输入而失败。因此,即使变量是datetime并且EffectiveDate没有时间部分,它仍然应该<=在该比较中,因此恰好在午夜的查询不会包含当天的数据。

PS 很抱歉没有保留您的格式——我只是在以我喜欢的样式格式化时更好地理解查询。此外,我将日期条件移至WHERE子句,因为在我看来它们不是JOIN.

于 2013-06-07T20:56:28.473 回答
-1

尝试使用 isnull 而不是 OR 语句。我还认为您应该使用 Datediff 而不是比较运算符。

select CustomerNumber, IdentificationNumber
From Identification i
Inner Join IdentificationType it On it.IdentificationType = i.IdentificationType
And it.EffectiveDate < @TodaysDate
And (isnull(it.EndDate,@TodaysDate) >= @TodaysDate)
于 2013-06-07T21:14:58.123 回答