web-dev-qa-db-ja.com

SQL ServerでのDateTime2とDateTime

どれ:

theはSQL Server 2008以降で日付と時刻を保存する方法として推奨されますか。

私は精度(そしておそらくストレージスペース)の違いを知っていますが、今のところそれらを無視して、何を使うべきかについてのベストプラクティスドキュメントはありますか、あるいは単にdatetime2だけを使うべきですか?

683
Mikeon

datetime のMSDNドキュメントでは datetime 2 の使用を推奨しています。これが彼らの勧告です。

新規の作業にはtimedatedatetime2およびdatetimeoffsetデータ型を使用してください。これらの型は標準SQLに準拠しています。彼らはよりポータブルです。 timedatetime2、およびdatetimeoffsetは秒精度を高めます。 datetimeoffsetは、グローバルにデプロイされたアプリケーションにタイムゾーンサポートを提供します。

datetime2は、より大きい日付範囲、より大きいデフォルト小数位数精度、およびオプションのユーザー指定精度を持ちます。また、ユーザー指定の精度によっては、使用する記憶域が少なくなることがあります。

567
Adam Porad

DATETIME2の日付範囲は "0001/01/01"から "9999/12/31"ですが、DATETIMEタイプは1753年から9999年までをサポートします。

また、必要に応じて、DATETIME2の方が時間的に正確な場合があります。 DATETIMEは3 1/3ミリ秒に制限されていますが、DATETIME2は100nsまで正確です。

どちらのタイプも.NETのSystem.DateTimeにマッピングされます - 違いはありません。

あなたが選択をするならば、私は可能な限りDATETIME2を使うことを勧めます。私はDATETIMEを使うことで何の利点も見られません(後方互換性を除いて) - あなたはより少ないトラブル(日付が範囲外でそのような面倒であること)を持つことになるでしょう。

さらに:日付だけが必要な場合(時間の部分はありません)、DATEを使用してください - DATETIME2と同じくらいよく、スペースも節約できます。 :-)これは時間だけのことです - TIMEを使ってください。それがこれらの型があるのです!

460
marc_s

datetime2以外のほとんどの面で勝ちます(旧アプリ互換性)

  1. 大きい値の範囲
  2. より良い正確さ
  3. 小さい記憶域(オプションのユーザー指定の精度が指定されている場合)

SQL Date and time data types compare - datetime,datetime2,date,TIME

以下の点に注意してください

  • 構文
    • datetime2 [(小数秒精度=>ストレージサイズ以下を参照)]
  • 精度、スケール
    • 100nsの精度で0から7桁。
    • デフォルトの精度は7桁です。
  • 収納サイズ
    • 精度が3未満の場合は6バイト。
    • 精度3および4の場合は7バイト。
    • 他のすべての精度8バイトが必要
  • DateTime2(3)はDateTimeと同じ桁数ですが、8バイトではなく7バイトのストレージを使用します( SQLHINTS - DateTimeとDateTime2
  • datetime2(Transact-SQL MSDNの記事)

画像ソース: MCTSセルフペーストレーニングキット(試験70-432):Microsoft®SQLServer®2008 - 導入および保守 第3章:テーブル - >レッスン1:テーブルの作成 - > 66ページ

183
Iman Abidi

@marc_sと@Adam_Powardに同意します - DateTime2は、今後の推奨方法です。これは、より広い範囲の日付、より高い精度を持ち、(精度に応じて)同等以下のストレージを使用します。

議論が失敗したことが1つありますが...
@ Marc_s氏は次のように述べています:Both types map to System.DateTime in .NET - no difference there。これは正しい、ただし、その逆は成り立ちません...そしてそれは日付範囲検索をするときに重要です(例えば、「5/5/2010に修正されたすべてのレコードを見つけてください」)。

.NETバージョンのDatetimeは、DateTime2と同様の範囲と精度を持ちます。 .netのDatetimeを古いSQLのDateTimeにマッピングするとき、暗黙的な丸めが行われます。古いSQLのDateTimeは3ミリ秒の精度です。これは11:59:59.997があなたが一日の終わりに到達することができるのと同じくらい近いことを意味します。それより高いものは翌日に切り上げられます。

これを試して :

declare @d1 datetime   = '5/5/2010 23:59:59.999'
declare @d2 datetime2  = '5/5/2010 23:59:59.999'
declare @d3 datetime   = '5/5/2010 23:59:59.997'
select @d1 as 'IAmMay6BecauseOfRounding', @d2 'May5', @d3 'StillMay5Because2msEarlier'

この暗黙的な丸めを避けることは、DateTime2に移行する重要な理由です。暗黙的に日付を丸めると、明らかに混乱が生じます。

103
EBarr

問題のフィールドにNow()を書き込もうとしているAccess開発者であれば、DateTime2は混乱を招きます。 Access - > SQL 2008 R2の移行を行ったところで、すべてのdatetimeフィールドがDateTime2になりました。値がNow()のレコードを追加しました。それは、2012年1月1日2時53分04秒大丈夫でしたが、2012年1月10日午後2時53分04秒ではありませんでした。

一度文字が違いを生んだ。誰かに役立つことを願っています。

15
Rhett A Brown

ほとんどすべての回答とコメントは長所に重点が置かれ、短所に軽くされています。これはこれまでのところすべての長所と短所に加えていくつかの重要な短所(下記#2)を要約したものです。

  1. PROS:

1.1。よりISO準拠(ISO 8601)(ただし、これが実際にどのように機能するのかはわかりません)。

1.2。より広い範囲(1/1/0001から12/31/9999対1/1/1753-12/31/9999)(ただし、1753年より前の追加の範囲は、例を除いて使用されない可能性があります。歴史的、天文学的、地質学的などのアプリで)。

1.3。 .NETのDateTimename__型の範囲と完全に一致します(ただし、値がターゲットの型の範囲と精度の範囲内である場合は特別なコーディングなしで前後に変換されますが、それ以外の場合はエラー/四捨五入が発生します)。

1.4。より高い精度(100ナノ秒、別名0.000,000、1秒対3.33ミリ秒、別名0.003,33秒)(ただし、特別な精度は、工学以外の用途では使用されない可能性がありますが、科学/科学アプリケーションでは)。

1.5。 類似(Iman Abidiが主張したのと同じ(1ミリ秒ではない)(3.33ミリ秒ではない)のように)の精度をDateTimename__と同じ精度に設定すると、使用するスペースは少なくなります(7対8バイト) 2つのうちの1つ(おそらくもう1つの範囲)の精度の利点を失うことになりますが、不要な利点の可能性はありますが)。

  1. 短所:

2.1。パラメータを.NETのSqlCommandname__に渡すとき、SQL ServerのDateTimenameの範囲や精度の外側に値を渡す場合は、System.Data.SqlDbType.DateTime2を指定する必要があります。デフォルトはSystem.Data.SqlDbType.DateTimeです。

2.2。 SQL Serverの式で数値と演算子を使用して暗黙的にまたは簡単に浮動小数点数値(最小日時からの経過日数)に変換することはできません。

2.2.1。日数または部分日数を加算または減算します。注:DateAddname__関数を回避策として使用することは、日時の一部ではないにしても複数を考慮する必要がある場合には簡単ではありません。

2.2.2。 「年齢」を計算するために、2つの日時の差を取ります。注:SQL ServerのDateDiffname__関数は単純に使用することはできません。2つの日付時刻がカレンダー/時計の日付時刻境界を超えても、ほとんどの人が予想するようにagename__が計算されないためです。その単位のごく一部で、その単位の1対0の差が返されます。たとえば、2つの日付時刻がわずか1ミリ秒のDateDiffname__のDayname__は、それらの日付の場合1対0(日)を返します。時間は異なる暦日にあります(すなわち、「1999-12-31 23:59:59.9999999」と「2000-01-01 00:00:00.0000000」)。暦日をまたがないように移動した場合、同じ1ミリ秒の差分日時は、0(日)のDayname__に「DateDiff」を返します。

2.2.3。最初に "Float"に変換してから、再度Avgname__に戻すことで、(集約クエリで)date-timesのDateTimename__を取得します。

注:DateTime2を数値に変換するには、次の公式のようにしなければなりません。これは、値が1970年より小さくないことを前提としています。数値のオーバーフローの問題に遭遇する可能性があるため、余分な範囲を考慮して式を単純に調整できない場合があります。

25567 + (DATEDIFF(SECOND, {d '1970-01-01'}, @Time) + DATEPART(nanosecond, @Time) / 1.0E + 9) / 86400.0 - 出典:“ https://siderite.blogspot.com/2015/08/how-to-translate-t-sql-datetime2-to.html

もちろん、最初にCastname__からDateTimename__に(そして必要ならば再びDateTime2に戻すことも)できますが、DateTime2DateTimename__の2つの長さの精度と範囲の利点が失われることになります。同時に2つの可能性が最も低いので、足し算/引き算/ "age"に対して暗黙の/簡単な浮動小数点数(日数)への変換を失うときになぜ使うべきかという疑問を投げかける(DateDiffname__)/ Avgcalcsの利点は、私の経験では大きなものです。

ところで、date-timesのAvgname__は(または少なくともshould be)重要なユースケースです。 a)(共通の基準日時なので)日時が期間を表すのに使われるときの平均期間の取得(一般的な慣例)以外に、b)平均日時のダッシュボード型の統計を取得するのも便利です。 timeは、行の範囲/グループの日時列にあります。 c)カラムの値を監視/トラブルシューティングするための標準的な(または少なくともすべき標準的な)アドホッククエリ。値ごとに、出現回数、および(使用可能な場合は)その値に関連付けられているMinname__、Avgname__、およびMaxname__の日時スタンプ。

13
Tom

これは、smalldatetime、datetime、datetime2(0)、およびdatetime2(7)の間のストレージサイズ(バイト)と精度の違いを示す例です。

DECLARE @temp TABLE (
    sdt smalldatetime,
    dt datetime,
    dt20 datetime2(0),
    dt27 datetime2(7)
)

INSERT @temp
SELECT getdate(),getdate(),getdate(),getdate()

SELECT sdt,DATALENGTH(sdt) as sdt_bytes,
    dt,DATALENGTH(dt) as dt_bytes,
    dt20,DATALENGTH(dt20) as dt20_bytes,
    dt27, DATALENGTH(dt27) as dt27_bytes FROM @temp

戻る

sdt                  sdt_bytes  dt                       dt_bytes  dt20                 dt20_bytes  dt27                         dt27_bytes
2015-09-11 11:26:00  4          2015-09-11 11:25:42.417  8         2015-09-11 11:25:42  6           2015-09-11 11:25:42.4170000  8

ミリ秒単位ではなく秒単位で情報を保存したいのであれば、datetimeまたはdatetime2(7)の代わりにdatetime2(0)を使用すれば、それぞれ2バイト節約できます。

13
Baodad

precision with datetime2 が増加している間、datetime、またはdatetime2をサポートしないクライアントもあります。文字列リテラルに変換します。特にMicrosoftは、これらのデータ型に関する "下位レベルの" ODBC、OLE DB、JDBC、およびSqlClientの問題に言及しており、それぞれがどのように型をマッピングできるかを示す chart を持ちます。

互換性 精度を超えている場合は、 datetime を使用します。

8
FistOfFury

datetimedatetime2への日付文字列の解釈も、米国以外のDATEFORMAT設定を使用する場合は異なる場合があります。例えば。

set dateformat dmy
declare @d datetime, @d2 datetime2
select @d = '2013-06-05', @d2 = '2013-06-05'
select @d, @d2

これは、datetimeに対して2013-05-06(すなわち5月6日)を、そして2013-06-05に対してdatetime2(すなわち6月5日)を返す。ただし、dateformatmdyに設定すると、@d@d2の両方が2013-06-05を返します。

datetimeの振る舞いは、 MSDNドキュメントSET DATEFORMATの/と矛盾するようです:ISO 8601などの一部の文字列フォーマットは、DATEFORMAT設定とは無関係に解釈されます。明らかにそうではありません!

私がこれに噛まれるまで、私はyyyy-mm-ddの日付は言語/ロケールの設定に関わらず、正しく扱われることを常に考えていました。

7
Richard Fawcett

昔の質問...しかし、ここにだれかによってまだ述べられていないものを追加したいのですが…(注:これは私自身の見解です。

Datetime2は、フィルタ条件で使用すると速くなります。

TLDR:

SQL 2016では、正確な時間を秒単位で格納する必要があるため、10万行のテーブルと日時列ENTRY_TIMEがありました。多数の結合とサブクエリを含む複雑なクエリを実行しているときに、where句を次のように使用すると、

WHERE ENTRY_TIME >= '2017-01-01 00:00:00' AND ENTRY_TIME < '2018-01-01 00:00:00'

最初は数百行あるときにクエリは問題ありませんでしたが、行数が増えると、クエリは次のエラーを出し始めました。

Execution Timeout Expired. The timeout period elapsed prior
to completion of the operation or the server is not responding.

Where句を削除しましたが、予想外にも1秒でクエリが実行されましたが、現在ではすべての日付のすべての行が取得されています。 where句を使用して内部クエリを実行したところ、85秒かかりました。where句がないと、0.01秒かかりました。

私は datetime filtering performance としてこの問題についてここで多くのスレッドに出会いました

クエリを少し最適化しました。しかし、私が本当に得た速度は、datetimeカラムをdatetime2に変更することでした。

これまでにタイムアウトしたクエリと同じクエリが1秒もかからないようになりました。

乾杯

6
Khan

この記事によると 、もしあなたがDateTime2を使ってDateTimeと同じ精度を得たいのであれば、単にDateTime2(3)を使わなければなりません。これにより、同じ精度が得られ、1バイト少なくなり、範囲が広がります。

4
jKlaus

私はDATETIME2のもう一つの利点に遭遇しました:それは標準ライブラリadodbapiname__値が渡された場合に発生するPython datetimename__モジュールのバグを回避しますが、DATETIMEname__列に対して定義された場合DATETIME2

3
Bob Kline
Select ValidUntil + 1
from Documents

上記のSQLはDateTime2フィールドでは動作しません。 「Operand type clash:datetime2はintと互換性がありません」というエラーが返されます。

次の日に1を加えることは、開発者が何年もの間日付を使ってやってきたことです。今すぐMicrosoftはこの単純な機能を処理することができない超新しいdatetime2フィールドを持っています。

「古いタイプよりも悪いこの新しいタイプを使用しましょう」、私はそうは思わない!

0
Paul McCarthy

DATETIME2はDATETIMEよりも効率が良いので、日付を保存するためのより良い方法だと思います。 SQL Server 2008ではDATETIME2を使用できます。日付と時刻を格納し、格納に6〜8バイトを要し、100ナノ秒の精度を持ちます。もっと大きな時間精度を必要とする人は誰でもDATETIME2が欲しいでしょう。

0
James