这里就是我的使用:

SELECT CAST(FLOOR(CAST(getdate() as FLOAT)) as DATETIME)

我想可能有一个更美好和更优雅的方式。

要求:

  • 它必须尽可能快的(少铸好)。
  • 最终结果是一个 datetime 类型,不一串。
有帮助吗?

解决方案

SQL服务器2008年

在SQL服务器2008年,当然最快的方法是 Convert(date, @date).这个可以转换回 datetimedatetime2 如果有必要的。

什么是真正的最佳SQL服务器2005年和老?

我见过的不一致要求关于什么是最快的截断的时间从一个日期在SQL服务器,有些人甚至说他们做了试验,但我的经验已经不同。因此,让我们做一些更严格的测试并让每个人都有剧本所以,如果我犯任何错误,人们可以纠正我。

浮动转换并不准确

首先,我要远离转换 datetimefloat, 因为它不转换成正确的。你可能得到与做的时去除的事情准确的,但我认为这是个坏主意使用它,因为它隐含地进行通信,以开发,这是一个安全操作和 它不是.看一看:

declare @d datetime;
set @d = '2010-09-12 00:00:00.003';
select Convert(datetime, Convert(float, @d));
-- result: 2010-09-12 00:00:00.000 -- oops

这是不是我们应该教导人们在我们的码或在我们的实例在线。

还有,它甚至不是最快的方式!

证明性能的测试

如果你要执行一些试验自己,看看如何在不同的方法真的做堆起来,然后你会需要这个安装脚本运行测试远下:

create table AllDay (Tm datetime NOT NULL CONSTRAINT PK_AllDay PRIMARY KEY CLUSTERED);
declare @d datetime;
set @d = DateDiff(Day, 0, GetDate());
insert AllDay select @d;
while @@ROWCOUNT != 0
   insert AllDay
   select * from (
      select Tm =
         DateAdd(ms, (select Max(DateDiff(ms, @d, Tm)) from AllDay) + 3, Tm)
      from AllDay
   ) X
   where Tm < DateAdd(Day, 1, @d);
exec sp_spaceused AllDay;  -- 25,920,000 rows

请注意,这将创建一个427.57MB表,在你的数据库,并将采取什么样的15-30分钟的运行。如果你的数据库是小和设置10%的增长,它将需要更长的时间超过如果你的大小足够大的第一个。

现在的实际性能测试脚本。请注意,这是有目的的不返回的行回客户,因为这是疯狂的昂贵月26亿行,并将隐藏的业绩之间的差异的方法。

性能的结果

set statistics time on;
-- (All queries are the same on io: logical reads 54712)
GO
declare
    @dd date,
    @d datetime,
    @di int,
    @df float,
    @dv varchar(10);

-- Round trip back to datetime
select @d = CONVERT(date, Tm) from AllDay; -- CPU time = 21234 ms,  elapsed time = 22301 ms.
select @d = CAST(Tm - 0.50000004 AS int) from AllDay; -- CPU = 23031 ms, elapsed = 24091 ms.
select @d = DATEDIFF(DAY, 0, Tm) from AllDay; -- CPU = 23782 ms, elapsed = 24818 ms.
select @d = FLOOR(CAST(Tm as float)) from AllDay; -- CPU = 36891 ms, elapsed = 38414 ms.
select @d = CONVERT(VARCHAR(8), Tm, 112) from AllDay; -- CPU = 102984 ms, elapsed = 109897 ms.
select @d = CONVERT(CHAR(8), Tm, 112) from AllDay; -- CPU = 103390 ms,  elapsed = 108236 ms.
select @d = CONVERT(VARCHAR(10), Tm, 101) from AllDay; -- CPU = 123375 ms, elapsed = 135179 ms.

-- Only to another type but not back
select @dd = Tm from AllDay; -- CPU time = 19891 ms,  elapsed time = 20937 ms.
select @di = CAST(Tm - 0.50000004 AS int) from AllDay; -- CPU = 21453 ms, elapsed = 23079 ms.
select @di = DATEDIFF(DAY, 0, Tm) from AllDay; -- CPU = 23218 ms, elapsed = 24700 ms
select @df = FLOOR(CAST(Tm as float)) from AllDay; -- CPU = 29312 ms, elapsed = 31101 ms.
select @dv = CONVERT(VARCHAR(8), Tm, 112) from AllDay; -- CPU = 64016 ms, elapsed = 67815 ms.
select @dv = CONVERT(CHAR(8), Tm, 112) from AllDay; -- CPU = 64297 ms,  elapsed = 67987 ms.
select @dv = CONVERT(VARCHAR(10), Tm, 101) from AllDay; -- CPU = 65609 ms, elapsed = 68173 ms.
GO
set statistics time off;

一些散漫的分析

一些说明这一点。首先,如果只是执行一个集团或一个比较,就没有必要转换回来 datetime.这样你可以节省一些CPU通过避免的是,除非你需要的最终价值显示的目的。你甚至可以组的未转化价值,并把换只有在选择条款:

select Convert(datetime, DateDiff(dd, 0, Tm))
from (select '2010-09-12 00:00:00.003') X (Tm)
group by DateDiff(dd, 0, Tm)

此外,看到数字转换,只需要稍微更多的时间转换回来 datetime, 但 varchar 转换几乎翻倍?这揭示了该部分的CPU是专门讨论日期计算在查询。有部分占用,不涉及日期计算,这似乎是一些接近19875ms在上述查询。然后转换需要一些额外的金额,所以如果有两个转换,这一数额是用了大约两倍。

更多的审查显示,相比于 Convert(, 112), , Convert(, 101) 查询有一些额外的CPU费用(因为它使用一个更长的 varchar?), 因为第二次转换回来 date 成本不尽最初的转换 varchar, 但与 Convert(, 112) 它是更接近于同20000ms CPU基础的成本。

这里是这些计算的CPU时间,我用的上述分析:

     method   round  single   base
-----------  ------  ------  -----
       date   21324   19891  18458
        int   23031   21453  19875
   datediff   23782   23218  22654
      float   36891   29312  21733
varchar-112  102984   64016  25048
varchar-101  123375   65609   7843
  • 是的CPU时间返回 datetime.

  • 是CPU时间为一个单一的转换到备用数据的类型(一个具有副作用的除去的时间部分)。

  • 基地 是的计算,减去从 single 两者之间的差异调用: single - (round - single).这是一个大概的数字,假定的转换,数据的类型和 datetime 大约是相同的。出现这种假设是不完美的,但是接近,因为价值是所有靠近20000ms只有一个例外。

一个更有趣的事情是基本成本几乎等于单 Convert(date) 方法(其中有几乎0成本,因为服务器,可以在内部提取整天部右侧的第一个四字节的 datetime 数据类型)。

结论

那么是什么它看起来像是单方向 varchar 转化方法需要大约1.8微秒和用单方向 DateDiff 方法需要大约0.18μs。我基本上最保守的"基CPU"时间在我的测试18458ms总25,920,000行,因此23218ms/25920000=0.18μs。明显的10倍的改善似乎很多,但是坦率地说相当小,直到您正在处理成千上万的排(617k行=1第二节余)。

甚至给这个小的绝对改善,在我看来, DateAdd 方法的胜利,因为它是最佳组合的业绩和透明度。答案,需要一"神奇数字"的 0.50000004 是要咬人的某一天(零五或六个???), 再加上很难理解。

附加说明

当我得到一些时间我要改变 0.50000004'12:00:00.003' 看看它是如何做。这是转换成相同的 datetime 值和我发现它很容易记得.

对于那些有兴趣,上述试验是在服务器上运行哪里@@版本的回报如下:

Microsoft SQL Server2008(题)-10.0.1600.22(英特尔X86)Jul9 2008 14:43:34Copyright(c)1988-2008微软公司的标准版本的Windows NT5.2(建立3790:Service Pack2)

其他提示

SQL服务器2008年有一个新的 日期 数据类型 这简化了这个问题:

SELECT CAST(CAST(GETDATE() AS date) AS datetime)

伊茨克Ben-Gan在 DATETIME计算,第1部分 (SQL服务器杂志》,2007年)显示了三种方法进行这样转换(最慢的速度最快的;之间的差别的第二和第三种方法是较小的):

SELECT CAST(CONVERT(char(8), GETDATE(), 112) AS datetime)

SELECT DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)

SELECT CAST(CAST(GETDATE() - 0.50000004 AS int) AS datetime)

你的技术(铸造 漂浮)是建议由一个读者在四月的问题的杂志。根据他的说法,它具有性能相当于第二技术提出上述。

你的 CAST-FLOOR-CAST 似乎已经是最佳的方式,至少在MS SQL Server2005年。

一些其他的解决方案,我看到的有一串转换,喜欢 Select Convert(varchar(11), getdate(),101) 在他们的,这是速度较慢的10倍。

请尝试:

SELECT CONVERT(VARCHAR(10),[YOUR COLUMN NAME],105) [YOURTABLENAME]

SQL2005:我建议铸造而不是dateadd.例如,

select cast(DATEDIFF(DAY, 0, datetimefield) as datetime)

平均约10% 速度更快 在我的数据集,于

select DATEADD(DAY, DATEDIFF(DAY, 0, datetimefield), 0)

(铸造成smalldatetime快仍)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top