これが私が使用するものです:
SELECT CAST(FLOOR(CAST(getdate() as FLOAT)) as DATETIME)
もっと上品でエレガントな方法があるのではないかと思います。
要件:
- できるだけ速くする必要があります(キャストが少ないほど良い)。
- 最終的な結果は
datetime
、文字列ではなく型である必要があります。
これが私が使用するものです:
SELECT CAST(FLOOR(CAST(getdate() as FLOAT)) as DATETIME)
もっと上品でエレガントな方法があるのではないかと思います。
要件:
datetime
、文字列ではなく型である必要があります。回答:
SQL Server2008以降
もちろん、SQL Server 2008以降では、最速の方法はConvert(date, @date)
です。これは、datetime
またはdatetime2
必要に応じてキャストバックできます。
SQL Server 2005以前で本当に最高のものは何ですか?
SQL Serverの日付からの時間を切り捨てるのに最も速いものについて一貫性のない主張を見てきました。また、テストを行ったと言う人もいますが、私の経験は異なります。それでは、もっと厳しいテストを行い、全員にスクリプトを持たせて、間違いがあった場合に人々が私を訂正できるようにしましょう。
フロート変換は正確ではありません
まず、私は変換から離れて滞在するdatetime
にはfloat
、それが正しく変換されませんので、。時間の削除を正確に行うことでうまくいくかもしれませんが、これは安全な操作であり、そうではないことを開発者に暗黙的に伝えるため、使用するのは悪い考えだと思います。見てください:
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.57 MBのテーブルが作成され、実行に15〜30分かかることに注意してください。データベースが小さく、10%の拡張に設定されている場合、最初に十分なサイズを設定した場合よりも時間がかかります。
次に、実際のパフォーマンステストスクリプトについて説明します。これは2600万行で非常に高価であり、メソッド間のパフォーマンスの違いを隠すため、クライアントに行を返さないことが目的であることに注意してください。
パフォーマンス結果
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;
いくつかのとりとめのない分析
これについてのいくつかのメモ。まず、GROUP BYまたは比較を実行するだけの場合は、に変換し直す必要はありませんdatetime
。したがって、表示目的で最終値が必要でない限り、これを回避することでCPUを節約できます。変換されていない値をGROUPBYして、変換をSELECT句にのみ入れることもできます。
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
変換がほぼ2倍になることを確認してください。これにより、クエリの日付計算に専念しているCPUの部分が明らかになります。日付の計算を伴わないCPU使用率の部分があり、これは上記のクエリでは19875ミリ秒に近いもののようです。次に、変換には追加の量が必要になるため、変換が2つある場合、その量は約2回使用されます。
その他の検査はに比べてことが明らかになったConvert(, 112)
、Convert(, 101)
(それは長く使用しているため、クエリは、いくつかの追加のCPU費用を持っているvarchar
?)に第2の変換バックがあるため、date
への初期変換限り費用がかからないvarchar
で、しかしConvert(, 112)
それは近い同じ20000 msCPU基本コスト。
上記の分析に使用した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
roundは、に戻る往復のCPU時間ですdatetime
。
singleは、代替データ型(時間部分を削除するという副作用があるもの)への単一の変換のCPU時間です。
baseは、single
2つの呼び出しの差から減算する計算ですsingle - (round - single)
。これは、そのデータ型との間の変換を想定した球場の図でありdatetime
、どちらの方向でもほぼ同じです。この仮定は完全ではないようですが、1つの例外を除いて、値はすべて20000ミリ秒に近いため、近いです。
もう1つの興味深い点は、基本コストが単一のConvert(date)
方法とほぼ等しいことです(サーバーは、datetime
データ型の最初の4バイトから整数の日部分を内部的に抽出できるため、コストはほぼ0である必要があります)。
結論
つまり、一方向varchar
変換法は約1.8μs、一方向変換法は約0.18μsかかるように見えDateDiff
ます。これは、25,920,000行で合計18458ミリ秒のテストで最も保守的な「ベースCPU」時間に基づいているため、23218ミリ秒/ 25920000 =0.18μsです。明らかな10倍の改善はかなりのように思えますが、数十万行を処理するまでは率直に言ってかなり小さいです(617k行= 1秒の節約)。
この小さな絶対的な改善があったとしても、私の意見では、このDateAdd
方法はパフォーマンスと明快さの最良の組み合わせであるため、勝ちます。の「マジックナンバー」を必要とする答えは、0.50000004
いつか誰かを噛むことになるでしょう(5つのゼロまたは6 ???)、さらにそれは理解するのが難しいです。
その他の注意事項
時間があれ0.50000004
ば'12:00:00.003'
、に変更して、その動作を確認します。同じdatetime
値に変換され、覚えやすいと思います。
興味のある方のために、上記のテストは@@ Versionが以下を返すサーバーで実行されました。
Microsoft SQL Server 2008(RTM)-10.0.1600.22(Intel X86)2008年7月9日14:43:34 Copyright(c)1988-2008 Microsoft Corporation Standard Edition on Windows NT 5.2(Build 3790:Service Pack 2)
char
代わりに使用した場合、時間差はありますvarchar
か?
select round(sysdate) from dual
、SQLServerには間違いなく必要です。
date
は、上記のテストで示したように、データ型への変換が最も高速です。
SQL Server 2008には新しい日付データ型があり、これによりこの問題が次のように単純化されます。
SELECT CAST(CAST(GETDATE() AS date) AS datetime)
DATEADD(DATEDIFF())
したため、時間部分をカットする方法で例外が発生します。私はキャストするときに結果バックdatetime2
あなたの方法ではうまく動作しますselect cast(CAST(convert(datetime2(0), '0218-09-12', 120) AS date) as datetime2)
Itzik Ben-Gan in DATETIME Calculations、Part 1(SQL Server Magazine、2007年2月)は、このような変換を実行する3つの方法を示しています(最も遅い方法から最も速い方法、2番目と3番目の方法の違いは小さい)。
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)
あなたのテクニック(フロートへのキャスト)は、雑誌の4月号の読者によって提案されています。彼によると、それは上に提示された2番目の技術のそれに匹敵する性能を持っています。
SELECT CAST(CAST(GETDATE() - '12:00:00.003' AS int) AS datetime)
代わりに使用することをお勧めします。これは、私にとって何かを意味し、覚えやすいためです。
Convert(date, GetDate())
。
あなたCAST
- FLOOR
-CAST
すでに少なくともMS SQL Server 2005の上で、最適な方法であると思われます。
私が見た他のいくつかのソリューションにはSelect Convert(varchar(11), getdate(),101)
、それらのように文字列変換があり、10倍遅くなります。
SQL2005:dateaddの代わりにキャストすることをお勧めします。例えば、
select cast(DATEDIFF(DAY, 0, datetimefield) as datetime)
私のデータセットでは、平均して約10%高速です。
select DATEADD(DAY, DATEDIFF(DAY, 0, datetimefield), 0)
(そしてsmalldatetimeへのキャストはさらに高速でした)