SQL Server中从日期和时间获取日期的最有效方法?


74

在MS SQL 2000和2005中,给定日期时间,例如“ 2008-09-25 12:34:56”,获取仅包含“ 2008-09-25”的日期时间的最有效方法是什么?

在这里重复。


4
我很满意前三个答案都是不同的,这意味着这不是一个愚蠢的问题!:)
Matt Howells

Answers:


114

我必须承认,我以前从未见过Matt展示的下浮率转换。我必须对此进行测试。

我测试了一个纯选择(将返回日期和时间,而这不是我们想要的),这里是统治性解决方案(floor-float),这里提到了一个常见的“天真”方案(stringconvert),而这里提到的是使用(因为我认为这是最快的)。

我在运行Win 2003 SP2 Server的测试服务器MS SQL Server 2005上测试了查询,而Xeon 3GHz CPU运行在最大内存上(32位,因此约为3.5 Gb)。那天晚上我在这里,所以机器几乎没有负载空转。我已经掌握了一切。

这是我的测试运行中的日志,该日志是从一个大型表中选择的,该表包含从毫秒到毫秒的时间戳。这个特定的数据集包含2.5年以上的日期。该表本身有1.3亿行,所以这就是为什么我限制在前100万行。

SELECT TOP 1000000 CRETS FROM tblMeasureLogv2 
SELECT TOP 1000000 CAST(FLOOR(CAST(CRETS AS FLOAT)) AS DATETIME) FROM tblMeasureLogv2
SELECT TOP 1000000 CONVERT(DATETIME, CONVERT(VARCHAR(10), CRETS, 120) , 120) FROM tblMeasureLogv2 
SELECT TOP 1000000 DATEADD(DAY, DATEDIFF(DAY, 0, CRETS), 0) FROM tblMeasureLogv2

SQL Server解析和编译时间:CPU时间= 0毫秒,经过的时间= 1毫秒。

(受影响的1000000行)表'tblMeasureLogv2'。扫描计数1,逻辑读4752,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。

SQL Server执行时间:CPU时间= 422毫秒,经过的时间= 33803毫秒。

(受影响的1000000行)表'tblMeasureLogv2'。扫描计数1,逻辑读4752,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。

SQL Server执行时间:CPU时间= 625毫秒,经过的时间= 33545毫秒。

(受影响的1000000行)表'tblMeasureLogv2'。扫描计数1,逻辑读4752,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。

SQL Server执行时间:CPU时间= 1953毫秒,经过的时间= 33843毫秒。

(受影响的1000000行)表'tblMeasureLogv2'。扫描计数1,逻辑读4752,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。

SQL Server执行时间:CPU时间= 531毫秒,经过的时间= 33440毫秒。SQL Server解析和编译时间:CPU时间= 0毫秒,经过的时间= 1毫秒。

SQL Server执行时间:CPU时间= 0毫秒,经过的时间= 1毫秒。

我们在这里看到什么?

让我们关注CPU时间(我们正在研究转换),我们可以看到有以下数字:

Pure-Select:  422
Floor-cast:   625
String-conv: 1953
DateAdd:      531  

由此看来,DateAdd(至少在这种情况下)比现场直播方法要快一些。

在您去那里之前,我多次运行了此测试,查询的顺序已更改,结果相同。

这在我的服务器上有点奇怪吗?


5
一点也不奇怪。首先,我认为转换为浮点数是不好的做法,因为往返转换为日期时间是不可靠的。其次,请参阅这篇文章,对各种方法进行更多性能测试
ErikE 2010年

24
Select DateAdd(Day, DateDiff(Day, 0, GetDate()), 0)

DateDiff(Day,0,GetDate())与DateDiff(Day,'1900-01-01',GetDate())相同

由于DateDiff返回一个整数,因此您将获得自1900年1月1日以来经过的天数。然后将该整数天数添加到1900年1月1日。净效果是删除了时间分量。

我还应该提到,此方法适用于任何日期/时间部分(例如年,季度,月,日,小时,分钟和秒)。

Select  DateAdd(Year, DateDiff(Year, 0, GetDate()), 0)
Select  DateAdd(Quarter, DateDiff(Quarter, 0, GetDate()), 0)
Select  DateAdd(Month, DateDiff(Month, 0, GetDate()), 0)
Select  DateAdd(Day, DateDiff(Day, 0, GetDate()), 0)
Select  DateAdd(Hour, DateDiff(Hour, 0, GetDate()), 0)
Select  DateAdd(Second, DateDiff(Second, '20000101', GetDate()), '20000101')

最后一个(持续几秒钟)需要特殊处理。如果您使用1900年1月1日,则会出现错误。

两个日期时间列的差异导致运行时溢出。

您可以使用其他参考日期(例如2000年1月1日)来避免此错误。


您确定这是最有效的方法吗?
马特·豪威尔斯

我的测试表明,马特的方法稍快一些。我也觉得它更具可读性。
Darrel Miller's

2
在我看来,@ Dar转换为float的做法不佳,因为往返转换为datetime是不可靠的。请参阅此帖子以获取更多详细信息
ErikE 2010年

12
select cast(floor(cast(@datetime as float)) as datetime)

之所以有效,是因为将日期时间强制转换为浮点型可给出自1900年1月1日以来的天数(包括一天的小数部分)。对其进行地板处理将除去小数天并保留整天的数目,然后可以将其转换回日期时间。


我一直在使用相同的方法,并且效果很好。据我所记得,DATETIME实际上实际上是作为FLOAT存储的,因此该方法非常有效。我还记得曾经读过某个地方,它是Microsoft内部使用的。不确定SS2008是否仍然如此
kristof

4
SQL2008具有经过大量改进(和急需)的日期处理功能。这就像将datetime转换为新的日期类型一样简单。
马特·豪威尔斯

3
@kristof datetime实际不存储为浮点数。它是两个4字节的整数,第一个是自1900-1-1以来的天数,第二个是自午夜以来的1/300秒刻度。最后,在我看来,转换为浮点数是不明智的做法,因为往返转换为日期时间是不可靠的。请参阅此帖子以获取更多详细信息
ErikE 2010年

听起来好像是存储为定点,而不是内部浮点。
反向工程师

7

在SQL Server 2012中使用

select cast(getdate() as date)

2
确实如此,但问题是有关缺少date数据类型的旧版MS SQL 2000和2005 。
jpw


0

要获取YYYY-MM-DD,请使用:

select convert(varchar(10), getdate(), 120)

编辑:糟糕,他希望使用DateTime而不是字符串。与Oracle中的TRUNC()等效。您可以将我发布的内容投射回DateTime:

select convert(datetime, convert(varchar(10), getdate(), 120) , 120)

2
请注意,转换为varchar比较慢。有关更多详细信息,请参见这篇文章
ErikE 2010年





By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.