DateTime2 против DateTime в SQL Server
-
20-09-2019 - |
Вопрос
Который из них:
является в рекомендуемый способ хранения даты и времени в SQL Server 2008+?
Я знаю о различиях в точности (и, вероятно, пространстве для хранения), но пока игнорирую их, есть ли документ с наилучшей практикой о том, когда и что использовать, или, может быть, нам следует просто использовать datetime2
только?
Решение
Документация MSDN для дата - время рекомендует использовать дата - время2.Вот их рекомендация:
Используйте
time
,date
,datetime2
иdatetimeoffset
типы данных для нового работа.Эти типы соответствуют стандарту SQL .Они более портативны.time
,datetime2
иdatetimeoffset
обеспечьте большую точность в секундах.datetimeoffset
обеспечивает часовой пояс поддержка глобально развернутых приложений.
datetime2 имеет больший диапазон дат, большую дробную точность по умолчанию и необязательную точность, заданную пользователем.Также, в зависимости от заданной пользователем точности, он может использовать меньше памяти.
Другие советы
DATETIME2
имеет диапазон дат от "0001 / 01 / 01" до "9999 / 12 / 31", в то время как DATETIME
тип поддерживает только 1753-9999 годы выпуска.
Кроме того, если вам нужно, DATETIME2
может быть более точным с точки зрения времени;ДАТА-ВРЕМЯ ограничено 3 1/3 миллисекунды, в то время как DATETIME2
может быть с точностью до 100 нс.
Оба типа сопоставляются с System.DateTime
в .NET - никакой разницы нет.
Если у вас есть выбор, я бы рекомендовал использовать DATETIME2
когда это возможно.Я не вижу никаких преимуществ в использовании DATETIME
(за исключением обратной совместимости) - у вас будет меньше проблем (с выходом за пределы диапазона дат и тому подобными хлопотами).
Plus:если вам нужна только дата (без временной части), используйте DATE - это так же хорошо, как DATETIME2
и к тому же экономит вам место!:-) То же самое касается только времени - используйте TIME
.Вот для чего существуют эти типы!
дата - время2 выигрывает по большинству аспектов, за исключением (совместимость со старыми приложениями)
- более крупный диапазон значений
- лучше Точность
- меньший место для хранения (если указана необязательная пользовательская точность)
пожалуйста, обратите внимание на следующие моменты
- Синтаксис
- datetime2[(точность в доли секунды => Смотрите ниже размер хранилища)]
- Точность, масштаб
- от 0 до 7 цифр, с точностью до 100 нс.
- Точность по умолчанию составляет 7 цифр.
- Размер хранилища
- 6 байт для точности менее 3;
- 7 байт для точности 3 и 4.
- Вся остальная точность требуется 8 байт.
- Дата-время2(3) имеет то же количество цифр, что и DateTime, но использует 7 байт памяти вместо 8 байт (SQLHINTS- DateTime Против DateTime2)
- Узнайте больше на datetime2(статья Transact-SQL MSDN)
источник изображения :Набор для самостоятельного обучения MCTS (экзамен 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
ан происходит неявное округление.Старый 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.Неявное округление дат явно вызывает путаницу:
- Странное поведение даты и времени в SQL Server
- http://bytes.com/topic/sql-server/answers/578416-weird-millisecond-part-datetime-data-sql-server-2000-a
- SQL Server 2008 и миллисекунды
- 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
Почти во всех ответах и комментариях было много плюсов и мало минусов.Вот краткое изложение всех плюсов и минусов на данный момент, плюс некоторые важные минусы (в # 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
Диапазон типа (хотя оба преобразуют туда и обратно без специального кодирования, если значения находятся в пределах диапазона и точности целевого типа, за исключением приведенного ниже Con # 2.1, иначе возникнет ошибка / округление).
1.4.Более высокая точность (100 наносекунд, или 0,000,000, 1 сек.против.3,33 миллисекунды, или 0,003,33 сек.) (хотя дополнительная точность, скорее всего, не будет использоваться, за исключением, например, инженерных / научных приложений).
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.Не может быть неявно / легко преобразовано в числовое значение с плавающей запятой (количество дней с момента минимальной даты-времени), чтобы выполнить с ним следующие действия в выражениях SQL Server, используя числовые значения и операторы:
2.2.1.добавьте или вычтите количество дней или неполных дней.Примечание:Используя DateAdd
Функция в качестве обходного пути не является тривиальной, когда вам нужно учитывать несколько, если не все части даты-времени.
2.2.2.возьмите разницу между двумя датами-временем для целей расчета “возраста”.Примечание:Вы не можете просто использовать SQL Server DateDiff
Функция вместо этого, потому что она не вычисляет age
как и следовало ожидать большинству людей, если произойдет, что две даты-времени пересекут границу даты-времени календаря / часов для указанных единиц измерения, даже если для крошечной части этой единицы измерения, это вернет разницу как 1 от этой единицы измерения по сравнению0.Например, в DateDiff
в Day
’s из двух значений даты и времени с интервалом всего в 1 миллисекунду вернет 1 против0 (дней), если эти даты и время приходятся на разные календарные дни (т.е.“1999-12-31 23:59:59.9999999” и “2000-01-01 00:00:00.0000000”).Та же разница во времени даты в 1 миллисекунду, если ее переместить так, чтобы они не пересекали календарный день, вернет “DateDiff” в Day
’s из 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
Для DateTime
сначала (и при необходимости снова вернуться к DateTime2
), но вы потеряли бы преимущества точности и дальности (все до 1753 года) DateTime2
против. DateTime
которые, вероятно, являются 2 самыми большими и в то же время, вероятно, 2 наименее необходимыми, что вызывает вопрос, зачем использовать это, когда вы теряете неявные / простые преобразования в числовые значения с плавающей запятой (количество дней) для сложения / вычитания / "возраста" (против DateDiff
) / Avg
вычисляет выгоду, которая, по моему опыту, является большой.
Кстати, в Avg
даты-времени является (или, по крайней мере, следует быть) важным вариантом использования.а) Помимо использования для получения средней продолжительности, когда для представления продолжительности используются значения даты и времени (начиная с общей базовой даты и времени) (обычная практика), б) также полезно получать статистику типа панели мониторинга о том, какое среднее значение даты и времени находится в столбце дата-время диапазона / группы строк.в) стандарт (или, по крайней мере, следует быть стандартным) специальный запрос для мониторинга / устранения неполадок значений в столбце, который может быть недействительным когда-либо / дольше и / или, возможно, должен устареть, заключается в перечислении для каждого значения количества встречаемости и (если доступно) Min
, Avg
и Max
метки даты и времени, связанные с этим значением.
DateTime2 наносит ущерб, если вы являетесь разработчиком Access, пытающимся записать Now() в рассматриваемое поле.Только что выполнил миграцию Access -> SQL 2008 R2, и она поместила все поля datetime в качестве DateTime2.Добавление записи с помощью Now() в качестве разбомбленного значения.Это было нормально 1/1/2012, 2: 53: 04 вечера, но не 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).
Интерпретация строк даты в datetime
и datetime2
может отличаться и при использовании неамериканских 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 из SET DATEFORMAT
какие государства: Некоторые форматы символьных строк, например ISO 8601, интерпретируются независимо от настройки DATEFORMAT.Очевидно, что это неправда!
Пока меня это не укусило, я всегда думал, что yyyy-mm-dd
даты просто будут обрабатываться правильно, независимо от настроек языка / локали.
в то время как наблюдается повышенный точность с дата - время2, некоторые клиенты не поддерживают Дата, время, или дата - время2 и заставит вас преобразовать в строковый литерал.В частности, Microsoft упоминает проблемы ODBC "нижнего уровня", OLE DB, JDBC и SqlClient с этими типами данных и имеет диаграмма показывая, как каждый из них может сопоставить тип.
Если значение совместимость сверхточность, используйте дата - время
Старый вопрос...Но я хочу добавить кое-что, о чем здесь еще никто не говорил...(Примечание:Это мое собственное наблюдение, так что не просите никаких ссылок)
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 на datetime2.
Теперь тот же запрос, у которого ранее истекло время ожидания, занимает меньше секунды.
ваше здоровье
Согласно эта статья, если вы хотели бы иметь такую же точность DateTime , используя DateTime2 , вам просто нужно использовать DateTime2(3).Это должно обеспечить вам ту же точность, занимать на один байт меньше и обеспечивать расширенный диапазон.
Я только что наткнулся на еще одно преимущество для DATETIME2
:это позволяет избежать ошибки в Python adodbapi
модуль, который взрывается, если стандартная библиотека datetime
передается значение, которое имеет ненулевые микросекунды для DATETIME
столбец, но работает нормально, если столбец определен как DATETIME2
.
Select ValidUntil + 1
from Documents
Приведенный выше SQL не будет работать с полем DateTime2.Он возвращает и выдает ошибку "Столкновение типов операндов:datetime2 несовместим с int"
Добавление 1 для получения следующего дня - это то, что разработчики делали с датами в течение многих лет.Теперь у Microsoft есть супер новое поле datetime2, которое не может обрабатывать эту простую функциональность.
"Давайте использовать этот новый тип, который хуже старого", я так не думаю!
Я думаю, что DATETIME2
является лучшим способом хранения date
, потому что он обладает большей эффективностью, чем
тот DATETIME
.В SQL Server 2008
вы можете использовать DATETIME2
, он сохраняет дату и время, занимает 6-8 bytes
для хранения и имеет точность 100 nanoseconds
.Таким образом, любой, кому нужна большая точность во времени, захочет DATETIME2
.