web-dev-qa-db-ja.com

SQL Serverで日付と時刻から日付を取得する最も効率的な方法は?

MS SQL 2000および2005では、「2008-09-25 12:34:56」などの日時を指定すると、「2008-09-25」のみを含む日時を取得する最も効率的な方法は何ですか?

複製 ここ

73
Matt Howells

Mattがこれまでに示したフロアフロート変換を見たことがないことを認めなければなりません。これをテストする必要がありました。

純粋なselect(DateとTimeを返しますが、私たちが望むものではありません)、ここでの支配的なソリューション(floor-float)、ここで言及された一般的な「ナイーブ」なもの(stringconvert)、使用(私はそれが最速だと思った)。

最大メモリ(32ビット、約3.5 Gb)で実行されるXeon 3GHz CPUを搭載したWin 2003 SP2サーバーで実行されるテストサーバーMS SQL Server 2005でクエリをテストしました。私がいるのは夜なので、機械はほとんど負荷なしで空転します。私はそれをすべて自分自身に持っています。

以下は、ミリ秒レベルまで変化するタイムスタンプを含む大きなテーブルから選択したテスト実行のログです。この特定のデータセットには、2.5年にわたる日付が含まれます。テーブル自体には1億3,000万行以上あるため、上位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(少なくともこの特定のケースでは)がfloor-castメソッドよりもわずかに速いように思えます。

そこに行く前に、このテストを数回実行し、クエリの順序を変更して、同じような結果を得ました。

これはサーバー上で奇妙なものですか?

111
Tomas
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')

最後の1秒は、特別な処理が必要です。 1900年1月1日を使用すると、エラーが発生します。

2つの日時列の違いにより、実行時にオーバーフローが発生しました。

別の参照日付(2000年1月1日など)を使用して、このエラーを回避できます。

24
G Mastros
select cast(floor(cast(@datetime as float)) as datetime)

日付時刻を浮動小数点数にキャストすると、1900年1月1日以降の日数(1日の端数を含む)が得られるため、機能します。

12
Matt Howells

sQL Server 2012での使用

select cast(getdate() as date)
7
BrianMichaels
select cast(getdate()as varchar(11))as datetime
1
Aamod Chandra

YYYY-MM-DDを取得するには、次を使用します。

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

編集:おっと、文字列ではなくDateTimeが必要です。 OracleのTRUNC()と同等。私が投稿したものを取り、DateTimeに戻すことができます:

select convert(datetime, convert(varchar(10), getdate(), 120) , 120)
0
Erick B

CAST(FLOOR(CAST(yourdate AS DECIMAL(12, 5))) AS DATETIME)は、最高のパフォーマンスを発揮します。 SQLサーバーで時間のない日付を取得する の場合、証明とテストを見ることができます

0
Andrew dh

CONVERT、FLOOR、およびDATEDIFFはまったく同じように機能します。

SQL Serverのdatetimeデータ型からのみ日付部分を返す方法

0
Ricardo C

以下のリンクで説明されている3つの方法。どちらが最も速いかを判断するために、それらのパフォーマンスをテストしていません。

http://www.blackwasp.co.uk/SQLDateFromDateTime.aspx

0
BlackWasp