SQLServer2008以降
もちろん、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
を使用するため) ?)、date
への2回目の変換のため varchar
への最初の変換ほど費用はかかりません 、ただしConvert(, 112)
同じ20000ミリ秒の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
-
ラウンド
datetime
に戻るラウンドトリップのCPU時間です 。 -
シングル 代替データ型(時間部分を削除するという副作用があるもの)への単一の変換のCPU時間です。
-
ベース
single
から減算する計算です 2つの呼び出しの違い:single - (round - single)
。これは、そのデータ型とdatetime
との間の変換を想定した球場の図です。 どちらの方向でもほぼ同じです。この仮定は完全ではないようですが、1つの例外を除いて、値はすべて20000ミリ秒に近いため、近いです。
もう1つの興味深い点は、基本コストが単一のConvert(date)
とほぼ等しいことです。 メソッド(サーバーはdatetime
の最初の4バイトから整数の日部分を内部的に抽出できるため、コストはほぼ0である必要があります。 データ型)。
結論
つまり、一方向のvarchar
は、次のようになります。 変換方法には約1.8μsかかり、一方向のDateDiff
メソッドには約0.18μsかかります。これは、25,920,000行の合計18458ミリ秒のテストで最も保守的な「ベースCPU」時間に基づいているため、23218ミリ秒/25920000=0.18μsです。明らかな10倍の改善はかなりのように思えますが、数十万行を処理するまでは率直に言ってかなり小さいです(617k行=1秒の節約)。
この小さな絶対的な改善があったとしても、私の意見では、DateAdd
メソッドは、パフォーマンスと明快さの最良の組み合わせであるため、勝ちます。 0.50000004
の「マジックナンバー」を必要とする答え いつか誰かを噛むことになるでしょう(5つのゼロまたは6つ???)、さらにそれは理解するのが難しいです。
追記
時間があれば、0.50000004
を変更します to '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)