どれ:
theはSQL Server 2008以降で日付と時刻を保存する方法として推奨されますか。
私は精度(そしておそらくストレージスペース)の違いを知っていますが、今のところそれらを無視して、何を使うべきかについてのベストプラクティスドキュメントはありますか、あるいは単にdatetime2
だけを使うべきですか?
datetime のMSDNドキュメントでは datetime 2 の使用を推奨しています。これが彼らの勧告です。
新規の作業には
time
、date
、datetime2
およびdatetimeoffset
データ型を使用してください。これらの型は標準SQLに準拠しています。彼らはよりポータブルです。time
、datetime2
、およびdatetimeoffset
は秒精度を高めます。datetimeoffset
は、グローバルにデプロイされたアプリケーションにタイムゾーンサポートを提供します。
datetime2は、より大きい日付範囲、より大きいデフォルト小数位数精度、およびオプションのユーザー指定精度を持ちます。また、ユーザー指定の精度によっては、使用する記憶域が少なくなることがあります。
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
を使ってください。それがこれらの型があるのです!
datetime2以外のほとんどの面で勝ちます(旧アプリ互換性)
以下の点に注意してください
画像ソース: MCTSセルフペーストレーニングキット(試験70-432):Microsoft®SQLServer®2008 - 導入および保守 第3章:テーブル - >レッスン1:テーブルの作成 - > 66ページ
@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に移行する重要な理由です。暗黙的に日付を丸めると、明らかに混乱が生じます。
問題のフィールドにNow()を書き込もうとしているAccess開発者であれば、DateTime2は混乱を招きます。 Access - > SQL 2008 R2の移行を行ったところで、すべてのdatetimeフィールドがDateTime2になりました。値がNow()のレコードを追加しました。それは、2012年1月1日2時53分04秒大丈夫でしたが、2012年1月10日午後2時53分04秒ではありませんでした。
一度文字が違いを生んだ。誰かに役立つことを願っています。
ほとんどすべての回答とコメントは長所に重点が置かれ、短所に軽くされています。これはこれまでのところすべての長所と短所に加えていくつかの重要な短所(下記#2)を要約したものです。
1.1。よりISO準拠(ISO 8601)(ただし、これが実際にどのように機能するのかはわかりません)。
1.2。より広い範囲(1/1/0001から12/31/9999対1/1/1753-12/31/9999)(ただし、1753年より前の追加の範囲は、例を除いて使用されない可能性があります。歴史的、天文学的、地質学的などのアプリで)。
1.3。 .NETのDateTime
name__型の範囲と完全に一致します(ただし、値がターゲットの型の範囲と精度の範囲内である場合は特別なコーディングなしで前後に変換されますが、それ以外の場合はエラー/四捨五入が発生します)。
1.4。より高い精度(100ナノ秒、別名0.000,000、1秒対3.33ミリ秒、別名0.003,33秒)(ただし、特別な精度は、工学以外の用途では使用されない可能性がありますが、科学/科学アプリケーションでは)。
1.5。 類似(Iman Abidiが主張したのと同じ(1ミリ秒ではない)(3.33ミリ秒ではない)のように)の精度をDateTime
name__と同じ精度に設定すると、使用するスペースは少なくなります(7対8バイト) 2つのうちの1つ(おそらくもう1つの範囲)の精度の利点を失うことになりますが、不要な利点の可能性はありますが)。
2.1。パラメータを.NETのSqlCommand
name__に渡すとき、SQL ServerのDateTime
nameの範囲や精度の外側に値を渡す場合は、System.Data.SqlDbType.DateTime2
を指定する必要があります。デフォルトはSystem.Data.SqlDbType.DateTime
です。
2.2。 SQL Serverの式で数値と演算子を使用して暗黙的にまたは簡単に浮動小数点数値(最小日時からの経過日数)に変換することはできません。
2.2.1。日数または部分日数を加算または減算します。注:DateAdd
name__関数を回避策として使用することは、日時の一部ではないにしても複数を考慮する必要がある場合には簡単ではありません。
2.2.2。 「年齢」を計算するために、2つの日時の差を取ります。注:SQL ServerのDateDiff
name__関数は単純に使用することはできません。2つの日付時刻がカレンダー/時計の日付時刻境界を超えても、ほとんどの人が予想するようにage
name__が計算されないためです。その単位のごく一部で、その単位の1対0の差が返されます。たとえば、2つの日付時刻がわずか1ミリ秒のDateDiff
name__のDay
name__は、それらの日付の場合1対0(日)を返します。時間は異なる暦日にあります(すなわち、「1999-12-31 23:59:59.9999999」と「2000-01-01 00:00:00.0000000」)。暦日をまたがないように移動した場合、同じ1ミリ秒の差分日時は、0(日)のDay
name__に「DateDiff」を返します。
2.2.3。最初に "Float"に変換してから、再度Avg
name__に戻すことで、(集約クエリで)date-timesのDateTime
name__を取得します。
注: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 “
もちろん、最初にCast
name__からDateTime
name__に(そして必要ならば再びDateTime2
に戻すことも)できますが、DateTime2
とDateTime
name__の2つの長さの精度と範囲の利点が失われることになります。同時に2つの可能性が最も低いので、足し算/引き算/ "age"に対して暗黙の/簡単な浮動小数点数(日数)への変換を失うときになぜ使うべきかという疑問を投げかける(DateDiff
name__)/ Avg
calcsの利点は、私の経験では大きなものです。
ところで、date-timesのAvg
name__は(または少なくともshould be)重要なユースケースです。 a)(共通の基準日時なので)日時が期間を表すのに使われるときの平均期間の取得(一般的な慣例)以外に、b)平均日時のダッシュボード型の統計を取得するのも便利です。 timeは、行の範囲/グループの日時列にあります。 c)カラムの値を監視/トラブルシューティングするための標準的な(または少なくともすべき標準的な)アドホッククエリ。値ごとに、出現回数、および(使用可能な場合は)その値に関連付けられているMin
name__、Avg
name__、およびMax
name__の日時スタンプ。
これは、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バイト節約できます。
datetime
とdatetime2
への日付文字列の解釈も、米国以外の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日)を返す。ただし、dateformat
をmdy
に設定すると、@d
と@d2
の両方が2013-06-05
を返します。
datetime
の振る舞いは、 MSDNドキュメントSET DATEFORMAT
の/と矛盾するようです:ISO 8601などの一部の文字列フォーマットは、DATEFORMAT設定とは無関係に解釈されます。明らかにそうではありません!
私がこれに噛まれるまで、私はyyyy-mm-dd
の日付は言語/ロケールの設定に関わらず、正しく扱われることを常に考えていました。
昔の質問...しかし、ここにだれかによってまだ述べられていないものを追加したいのですが…(注:これは私自身の見解です。
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秒もかからないようになりました。
乾杯
この記事によると 、もしあなたがDateTime2を使ってDateTimeと同じ精度を得たいのであれば、単にDateTime2(3)を使わなければなりません。これにより、同じ精度が得られ、1バイト少なくなり、範囲が広がります。
私はDATETIME2
のもう一つの利点に遭遇しました:それは標準ライブラリadodbapi
name__値が渡された場合に発生するPython datetime
name__モジュールのバグを回避しますが、DATETIME
name__列に対して定義された場合DATETIME2
。
Select ValidUntil + 1
from Documents
上記のSQLはDateTime2フィールドでは動作しません。 「Operand type clash:datetime2はintと互換性がありません」というエラーが返されます。
次の日に1を加えることは、開発者が何年もの間日付を使ってやってきたことです。今すぐMicrosoftはこの単純な機能を処理することができない超新しいdatetime2フィールドを持っています。
「古いタイプよりも悪いこの新しいタイプを使用しましょう」、私はそうは思わない!
DATETIME2はDATETIMEよりも効率が良いので、日付を保存するためのより良い方法だと思います。 SQL Server 2008ではDATETIME2を使用できます。日付と時刻を格納し、格納に6〜8バイトを要し、100ナノ秒の精度を持ちます。もっと大きな時間精度を必要とする人は誰でもDATETIME2が欲しいでしょう。