我有两个表需要加入,第一个表包含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)
我的执行计划是在标识类型表上显示聚簇索引扫描,我假设它是因为join子句中的OR。
是否有更有效的加入方式,知道EndDate字段必须允许Null,还是实际的日期时间值?
答案 0 :(得分:2)
我知道你说EndDate
列必须允许NULL
,所以只是为了记录:最有效的方法是停止使用NULL
代替“无结束日期”在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
子句的糟糕表现中恢复过来。爆炸查询大小/复杂性是痛苦的,但与您现在处理的扫描相比,获得一些搜索的可能性是完全值得的。
你的不平等比较有些可疑:第一个应该有一个等号({1}}。您没有告诉我们日期列和<=
的数据类型,但最佳做法是设计一个系统,以便它不会因任何输入而失败。因此,即使变量为@TodaysDate
且datetime
没有时间部分,该比较仍应为EffectiveDate
,因此正好在午夜的查询不会包含该数据一天。
P.S。很抱歉没有保留您的格式 - 我只是在以我喜欢的格式进行格式化时更好地理解查询。此外,我将日期条件移至<=
条款,因为在我看来它们不属于WHERE
。
答案 1 :(得分:-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)