如何使这个语句更快:“paramDate between startDate and NULL”?

Posted

技术标签:

【中文标题】如何使这个语句更快:“paramDate between startDate and NULL”?【英文标题】:How to make faster this statement : "paramDate Between startDate and NULL"? 【发布时间】:2009-05-11 11:48:48 【问题描述】:

当 endDate 为空时,此查询需要很长时间(我认为它是关于 case 语句,在 case 语句之前它很快)

SELECT * 
FROM HastaKurumlari
WHERE CONVERT(SMALLDATETIME,'21-05-2009',103) 
BETWEEN startDate 
    AND (CASE WHEN endDate IS NULL THEN GETDATE() ELSE endDate END) 

当 endDate 为 null 时,我应该使用什么来加快速度?

【问题讨论】:

【参考方案1】:

这是没有 CONVERT 或 CASE 的查询:

SELECT * 
FROM HastaKurumlari
WHERE '21-05-2009' between startDate and IsNull(endDate,getdate())

为了确保 Sql Server 不会为每一行评估 getdate(),您可以缓存它,尽管我很确定 Sql Server 默认情况下足够智能:

declare @now datetime
set @now = getdate()

SELECT * 
FROM HastaKurumlari
WHERE '21-05-2009' between startDate and IsNull(endDate,@now)

发布查询计划有助于解释查询缓慢的原因:

SET SHOWPLAN_TEXT ON
go
SELECT * 
FROM HastaKurumlari
WHERE CONVERT(SMALLDATETIME,'21-05-2009',103) 
BETWEEN startDate 
    AND (CASE WHEN endDate IS NULL THEN GETDATE() ELSE endDate END)

【讨论】:

这比合并功能更容易,也比以前更快。但是,coalesce 也很有用。 Coalesce 和 IsNUll 之间的唯一区别是 Coalesce 可以接受两个以上的参数。例如,Coalesce(null,null,3) 将返回 3。 @Andomar:不太正确:语义略有不同,例如COALESCE 提升为“最高”数据类型,而 ISNULL 使用第一个找到的数据类型。此外,作为标准 SQL 的 COALESCE 更具可移植性。说到这一点,我更喜欢 CURRENT_TIMESTAMP 而不是 getdate()。 @onedaywhen:有趣!在这里找到了一个很好的例子:haacked.com/archive/2005/01/21/…【参考方案2】:

如果它对性能至关重要,那么也许只是不要使用null 作为开放结束日期 - 而是使用支持的最大日期时间(可能很多 9)。

我也会单独进行转换:

DECLARE @when datetime
SET @when = CONVERT(SMALLDATETIME,'21-05-2009',103) 

SELECT * 
  FROM HastaKurumlari
WHERE @when
BETWEEN startDate AND endDate

上面和你原来的还是有些不同的;如果你能解释一下GETDATE() 检查的intent,我可能会稍微整理一下(阅读:修复)。

【讨论】:

我认为 SQL Server 足够聪明,可以注意到“查询内”转换,并且只在任何表或索引扫描之前执行一次。 GETDATE() 最好设置 endDate。但是如果我查询过去,我需要将 endDate 设置为 when 或 DateAdd(d,1,@When)。但是这个查询仍然无法运行。因为我们的 endDate 仍然为 NULL。【参考方案3】:

作为起点,将 GETDATE() 分解为只调用一次,您应该会看到速度有所提高。

您编写它的方式是在每次 enddate 为空时要求对 GETDATE() 进行评估。

由于 GETDATE() 是一个 non-deterministic 函数,因此无法优化查询,并且往往会表现不佳。

【讨论】:

刚刚做了一个在超过一百万行上使用 getdate() 的查询,它和使用缓存日期的查询一样快。【参考方案4】:

你可以试试coalesce函数:

select * 
from HastaKurumlari
where convert(smalldatetime, '21-05-2009', 103) 
    between startDate and coalesce(endDate, getdate());

唯一确定的方法是尝试任何替代方案并查看为每个查询生成的执行计划。

【讨论】:

当给定日期早于当前日期并且 endDate 为空时,第二个的工作方式不完全相同。第一个将包括记录,第二个将省略它。 你知道哪个更快吗?(COALESCE 和 ISNULL) +1 好答案,我想知道性能问题是否在于将 smalldatimetime 与 getdate() 中的日期时间进行比较。也许 endDate 和 startDate 也有 datimetime 类型。

以上是关于如何使这个语句更快:“paramDate between startDate and NULL”?的主要内容,如果未能解决你的问题,请参考以下文章

如何使这个 for 循环更快?

如何使这个 for 循环更快?

短路是不是使程序的执行更快,并且分析在条件语句中首先放置的语句是不是值得? [关闭]

我将如何改进/使这个运行更快? [关闭]

SQL查询性能调优--如何使查询更快

如何使这个 mysqli 查询在 PHP 中运行得更快?