DateTime2 против DateTime в SQL Server
кто:
is the рекомендуемый способ хранения даты и времени в SQL Server 2008+?
Я знаю о различиях в точности (и пространстве для хранения, вероятно), но игнорируя их сейчас, есть ли документ о наилучшей практике, когда использовать то, что, или, может быть, мы должны просто использовать datetime2
только?
14 ответов
документация MSDN для datetime рекомендует использовать тип datetime2. Вот их рекомендация:
использовать
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.
оба типа карты System.DateTime
в .NET-никакой разницы нет.
если у вас есть выбор, я бы рекомендовал использовать DATETIME2
всякий раз, когда это возможно. Я не вижу преимущества использования DATETIME
(за исключением обратной совместимости) - у вас будет меньше проблем (с датами, находящимися вне диапазона и хлопот).
плюс: если вам нужна только дата (без времени), дата использования - это так же хорошо, как DATETIME2
и экономит вам место, тоже! :- ) То же самое касается только времени - используйте TIME
. Вот для чего существуют эти типы!
тип datetime2 wins в большинстве аспектов, кроме (совместимость старых приложений)
- больше диапазон значений
- лучше точность
- меньше место хранения (если указана дополнительная точность, указанная пользователем)
пожалуйста, обратите внимание на следующие моменты
- синтаксис
- datetime2 [(точность дробных секунд=> смотреть Ниже Размера Хранилища)]
- точность, масштаб
- 0 до 7 чисел, с точностью 100ns.
- точность по умолчанию-7 цифр.
- Размер Хранилища
- 6 байт для точности менее 3;
- 7 байт для точности 3 и 4.
- все остальные требуется 8 байт.
- тип datetime2(3) имейте такое же количество цифры как DateTime, но использует 7 байт хранения вместо 8 байт (SQLHINTS-DateTime Vs DateTime2)
- подробнее о datetime2 (статья Transact-SQL MSDN)
Источник изображения : MCTS Self-Paced Training Kit (Exam 70-432): Microsoft® SQL Server® 2008 - внедрение и обслуживание Глава 3: таблицы - > Урок 1: создание таблиц - > страница 66
Я согласен с @marc_s и @Adam_Poward -- DateTime2 является предпочтительным методом продвижения вперед. Он имеет более широкий диапазон дат, более высокую точность и использует равное или меньшее хранение (в зависимости от точности).
одну вещь дискуссия пропустила, однако...
@Marc_s государства: Both types map to System.DateTime in .NET - no difference there
. Это верно,однако обратное неверно...и это имеет значение при выполнении поиска диапазона дат (например, "найти мне все записи, измененные на 5/5/2010").
.NET версии Datetime
имеет сходную дальность и точность DateTime2
. При сопоставлении .net Datetime
вплоть до старого SQL DateTime
an неявное округление происходит. Старый 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. Неявное округление дат явно вызывает путаницу:
- странное поведение datetime в SQL Server
- http://bytes.com/topic/sql-server/answers/578416-weird-millisecond-part-datetime-data-sql-server-2000-a
- SQL Server 2008 и миллисекунды!--28-->
- http://improve.dk/archive/2011/06/16/getting-bit-by-datetime-rounding-or-why-235959-999-ltgt.aspx
- http://milesquaretech.com/Blog/post/2011/09/12/DateTime-vs-DateTime2-SQL-is-Rounding-My-999-Milliseconds!.aspx
DateTime2 наносит ущерб, если вы разработчик доступа, пытающийся написать сейчас () в рассматриваемое поле. Просто сделал миграцию Access - > SQL 2008 R2, и он поместил все поля datetime в качестве DateTime2. Добавление записи с Now () в качестве значения bombed out. Это было хорошо на 1/1/2012 2:53:04 pm, но не на 1/10/2012 2:53:04 часов.
Как только характер сделал разницу. Надеюсь, это кому-то поможет.
вот пример, который покажет вам различия в размере хранилища (байты) и точности между 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
поэтому, если я хочу сохранить информацию до второй - но не до миллисекунды - я могу сохранить 2 байта каждый, если я использую datetime2(0) вместо datetime или datetime2 (7).
почти все ответы и комментарии были тяжелыми на плюсы и легкие на минусы. Вот резюме всех плюсов и минусов до сих пор плюс некоторые важные минусы (в #2 ниже), которые я видел только один раз или вообще не видел.
- плюсы:
1.1. Более ISO-совместимый (ISO 8601) (хотя я не знаю, как это происходит на практике).
1.2. Больше ряда (1/1/0001 до 12/31/9999 против 1/1/1753-12/31/9999) (хотя экстра диапазон, все до 1753 года, скорее всего, не будет использоваться, за исключением ex. в историческом, астрономическом, геологическом и т. д. приложения.)
1.3. Точно соответствует диапазону .NET DateTime
диапазон типа (хотя оба преобразования назад и вперед без специального кодирования, если значения находятся в диапазоне и точности целевого типа, за исключением Con # 2.1 ниже, произойдет ошибка / округление).
1.4. Более высокая точность (100 нс ака 0.000,000,1 сек. против 3.33 миллисекунды ака 0.003, 33 сек.) (хотя дополнительная точность, вероятно, не будет использоваться, за исключением ex., в инженерных / научных приложениях).
1.5. При настройке для как (как в 1 мс Не "же" (как в 3.33 мс), а Иман Абиди заявил) точность как DateTime
, использует меньше места (7 против 8 байт), но тогда, конечно, вы потеряете преимущество точности, которое, вероятно, является одним из двух (другой диапазон), наиболее рекламируемым, хотя, вероятно, ненужным выгоды.)
- плюсы:
2.1. При передаче параметра в .NET SqlCommand
необходимо указать System.Data.SqlDbType.DateTime2
Если вы можете передавать значение за пределами SQL Server DateTime
’диапазон и/или точность, потому что по умолчанию System.Data.SqlDbType.DateTime
.
2.2. Невозможно неявно / легко преобразовать в числовое значение с плавающей запятой (#дней с момента min date-time), чтобы выполнить следующие действия в выражениях SQL Server с использованием числовых значений и операторы:
2.2.1. добавить или вычесть # дней или частичных дней. Примечание: Использование DateAdd
функция в качестве обходного пути не является тривиальной, когда вам нужно рассмотреть несколько, если не все части даты-времени.
2.2.2. возьмите разницу между двумя датами-временами для целей расчета "возраста". Примечание: Вы не можете просто использовать тег age
как и большинство людей ожидали бы в этом случае, если две даты-раз произойдет пересечь календарную / часовую дату-временную границу единиц, указанных, если даже для крошечной части этой единицы, она вернет разницу как 1 этой единицы против 0. Например,DateDiff
на Day
из двух дат-раз только 1 миллисекунда друг от друга вернет 1 против 0 (дней), если эти даты-раз в разные календарные дни (т. е. "1999-12-31 23: 59: 59.9999999" и "2000-01-01 00:00:00.0000000"). То же 1 раз разница в миллисекунды, если переехал, так что они не пересекаются календарный день верните "DateDiff" в Day
0 (дней).
2.2.3. взять Avg
даты-времени (в агрегированном запросе) путем простого преобразования в "Float" сначала, а затем обратно в DateTime
.
Примечание: конвертировать DateTime2
для числового вы должны сделать что-то вроде следующей формулы, которая по-прежнему предполагает, что ваши значения не меньше 1970 года (что означает, что вы теряете весь дополнительный диапазон плюс еще 217 лет. Примечание: Вы не можете быть в состоянии просто настроить формула для дополнительного диапазона, поскольку могут возникнуть проблемы с числовым переполнением.
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
to DateTime
сначала (и при необходимости обратно в DateTime2
), но вы потеряете точность и дальность (до 1753 года) преимущества DateTime2
и DateTime
которые prolly 2 самые большие и также на этих же время, вероятно, 2 наименее вероятно, что напрашивается вопрос, зачем использовать его, когда вы теряете неявные / простые преобразования в числовые числа с плавающей запятой (#дней) для сложения / вычитания / "возраст" (vs.DateDiff
) / Avg
calcs преимущество, которое является большим в моем опыте.
кстати,Avg
дата-время (или по крайней мере должны be) важный прецедент. a) кроме пользы в получать среднюю продолжительность когда дата-времена (с общей базовой даты-времени) использованы к представление продолжительности (обычная практика), Б) также полезно получить статистику типа панели мониторинга о том, что среднее время даты находится в столбце дата-время диапазона / группы строк. в) стандарт (или по крайней мере должны быть стандартным) специальный запрос для мониторинга / устранения неполадок значений в столбце, который может быть недействительным когда-либо / больше и / или, возможно, должен быть устаревшим, должен перечислить для каждого значения количество вхождений и (если доступно)Min
, Avg
и Max
метки даты и времени связано с этим значением.
интерпретация строк даты в datetime
и datetime2
может быть по-разному слишком, при использовании non-US DATEFORMAT
настройки. Е. Г.
set dateformat dmy
declare @d datetime, @d2 datetime2
select @d = '2013-06-05', @d2 = '2013-06-05'
select @d, @d2
возвращает 2013-05-06
(т. е. 6 мая) для datetime
и 2013-06-05
(т. е. 5 июня)datetime2
. Однако с dateformat
значение mdy
, и @d
и @d2
возвращение 2013-06-05
.
на datetime
поведение кажется противоречащим документация MSDN of SET DATEFORMAT
в которой говорится: некоторые строки символов форматы, например ISO 8601, интерпретируются независимо от параметра DATEFORMAT. Очевидно, неправда!
пока я не был укушен этим, я всегда думал, что yyyy-mm-dd
даты будут обрабатываться правильно, независимо от настроек языка / локали.
пока есть увеличение точность С тип datetime2 некоторые клиенты не поддерживают дата, времени или тип datetime2 и заставить вас преобразовать в строковый литерал. В частности, Microsoft упоминает проблемы ODBC, OLE DB, JDBC и SqlClient" нижнего уровня " с этими типами данных и имеет диаграммы показывает, как каждый может сопоставить тип.
, Если значение совместимость за точностью, используйте datetime
по данным в этой статье, Если вы хотите иметь такую же точность DateTime с помощью DateTime2, вам просто нужно использовать DateTime2 (3). Это должно дать вам такую же точность, занять на один байт меньше и обеспечить расширенный диапазон.
Я просто наткнулся на еще одно преимущество для DATETIME2
: Это позволяет избежать ошибки в Python adodbapi
модуль, который взрывается, если стандартная библиотека datetime
передается значение, которое имеет ненулевые микросекунды для DATETIME
столбец, но работает нормально, если столбец определен как DATETIME2
.
Старый Вопрос... Но я хочу добавить кое-что, чего здесь еще никто не говорил... (Примечание: это мое собственное наблюдение, поэтому не просите никакой ссылки)
Datetime2 быстрее при использовании в критериях фильтра.
TLDR:
в SQL 2016 у меня была таблица со ста тысячами строк и столбцом datetime 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
Я немного оптимизировал запрос. Но реальная скорость у меня была при смене столбец datetime в datetime2.
теперь тот же запрос, который истекал ранее, занимает меньше секунды.
ура
Select ValidUntil + 1
from Documents
приведенный выше SQL не будет работать с полем DateTime2. Он возвращает и ошибку "столкновение типа операнда: datetime2 несовместимо с int"
добавление 1 для получения следующего дня-это то, что разработчики делали с датами в течение многих лет. Теперь у Microsoft есть супер новое поле datetime2, которое не может обрабатывать эту простую функциональность.
"давайте использовать этот новый тип, который хуже, чем старый", я так не думаю!
Я думаю, что DATETIME2-лучший способ сохранить дату, потому что он имеет больше эффективности, чем значение datetime. В SQL Server 2008 можно использовать DATETIME2, он хранит дату и время, занимает 6-8 байт для хранения и имеет точность 100 наносекунд. Поэтому любой, кому нужна большая точность времени, захочет DATETIME2.