在SQL Server中从datetime字段中删除时间部分时,哪种方法提供了最佳性能?

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

or

b) select cast(convert(char(11), getdate(), 113) as datetime)

第二种方法确实发送了更多的字节,但这可能没有转换速度那么重要。

两者看起来也都非常快,但在处理数十万行或更多行的时候,速度可能会有所不同。

此外,是否可能有更好的方法来消除SQL中datetime的时间部分?


当前回答

严格来说,方法a是资源密集度最低的:

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

经过证明,在相同的总持续时间内,对于那些有太多时间的人来说,更少的CPU密集型:SQL Server中从日期+时间获得日期的最有效方法?

我在其他地方看到了类似的测试,结果也类似。

我更喜欢DATEADD/DATEDIFF,因为:

Varchar受语言/日期格式问题的影响 示例:为什么我的CASE表达式是非确定性的? Float依赖于内部存储 它扩展到通过改变“0”基数来计算每月的第一天、明天等

编辑,2011年10月

对于SQL Server 2008+,您可以CAST到日期,即CAST(getdate() AS date)。或者只是使用日期数据类型,所以没有时间删除。

编辑,2012年1月

这是多么灵活的一个工作示例:需要在sql server中按四舍五入的时间或日期图进行计算

编辑,2012年5月

不要在WHERE子句和类似的地方使用这个:向列添加函数或CAST会使索引使用无效。参见第2条SQL编程常见错误

现在,这确实有一个SQL Server优化器版本正确管理CAST到日期的例子,但通常这将是一个坏主意…

编辑,2018年9月,datetime2

DECLARE @datetime2value datetime2 = '02180912 11:45' --this is deliberately within datetime2, year 0218
DECLARE @datetime2epoch datetime2 = '19000101'

select DATEADD(dd, DATEDIFF(dd, @datetime2epoch, @datetime2value), @datetime2epoch)

其他回答

就我个人而言,如果处理SQL Server 2005(或更低版本),几乎总是使用用户定义函数,然而,应该注意的是,使用UDF有特定的缺点,特别是如果将它们应用于WHERE子句(参见下面和对这个答案的评论了解更多细节)。如果使用SQL Server 2008(或更高版本)-请参见下面。

事实上,对于我创建的大多数数据库,我都是在一开始就添加这些UDF,因为我知道早晚有99%的可能性会用到它们。

我为“仅限日期”和“仅限时间”创建了一个(尽管“仅限日期”是迄今为止使用最多的一个)。

以下是一些与日期相关的UDF的链接:

基本SQL Server日期,时间和DateTime函数 只获取日期函数

最后一个链接显示了不少于3种获取datetime字段部分日期的不同方法,并提到了每种方法的优缺点。

If using a UDF, it should be noted that you should try to avoid using the UDF as part of a WHERE clause in a query as this will greatly hinder performance of the query. The main reason for this is that using a UDF in a WHERE clause renders that clause as non-sargable, which means that SQL Server can no longer use an index with that clause in order to improve the speed of query execution. With reference to my own usage of UDF's, I'll frequently use the "raw" date column within the WHERE clause, but apply the UDF to the SELECTed column. In this way, the UDF is only applied to the filtered result-set and not every row of the table as part of the filter.

当然,最好的方法是使用SQL Server 2008(或更高版本)并分离出您的日期和时间,因为SQL Server数据库引擎随后会本地提供单独的日期和时间组件,并且可以有效地独立查询这些组件,而不需要UDF或其他机制来从复合datetime类型中提取日期或时间部分。

SELECT CAST(CAST(GETDATE() AS DATE) AS DATETIME)
SELECT CAST(FLOOR(CAST(getdate() AS FLOAT)) AS DATETIME)

...根据下面的评论,这不是一个好的解决方案。

我想删除这个答案,但我把它留在这里作为一个反例,因为我认为评论者对为什么它不是一个好主意的解释仍然有用。

严格来说,方法a是资源密集度最低的:

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

经过证明,在相同的总持续时间内,对于那些有太多时间的人来说,更少的CPU密集型:SQL Server中从日期+时间获得日期的最有效方法?

我在其他地方看到了类似的测试,结果也类似。

我更喜欢DATEADD/DATEDIFF,因为:

Varchar受语言/日期格式问题的影响 示例:为什么我的CASE表达式是非确定性的? Float依赖于内部存储 它扩展到通过改变“0”基数来计算每月的第一天、明天等

编辑,2011年10月

对于SQL Server 2008+,您可以CAST到日期,即CAST(getdate() AS date)。或者只是使用日期数据类型,所以没有时间删除。

编辑,2012年1月

这是多么灵活的一个工作示例:需要在sql server中按四舍五入的时间或日期图进行计算

编辑,2012年5月

不要在WHERE子句和类似的地方使用这个:向列添加函数或CAST会使索引使用无效。参见第2条SQL编程常见错误

现在,这确实有一个SQL Server优化器版本正确管理CAST到日期的例子,但通常这将是一个坏主意…

编辑,2018年9月,datetime2

DECLARE @datetime2value datetime2 = '02180912 11:45' --this is deliberately within datetime2, year 0218
DECLARE @datetime2epoch datetime2 = '19000101'

select DATEADD(dd, DATEDIFF(dd, @datetime2epoch, @datetime2value), @datetime2epoch)

select CONVERT(char(10), GetDate(),126)