DateTime2 против DateTime в SQL Server - PullRequest
       99

DateTime2 против DateTime в SQL Server

690 голосов
/ 26 августа 2009

Какой:

- это рекомендуемый способ хранения даты и времени в SQL Server 2008 +?

Я знаю о различиях в точности (и, возможно, о размере места для хранения), но игнорируя их на данный момент, есть ли документ о передовой практике, когда что использовать, или, может быть, нам следует просто использовать только datetime2?

Ответы [ 14 ]

578 голосов
/ 11 декабря 2009

В документации MSDN для datetime рекомендуется использовать datetime2 . Вот их рекомендация:

Используйте time, date, datetime2 и datetimeoffset типы данных для новых Работа. Эти типы соответствуют SQL Стандарт. Они более портативны. time, datetime2 и datetimeoffset обеспечить больше секунд точности. datetimeoffset обеспечивает часовой пояс поддержка глобально развернутых приложения.

datetime2 имеет больший диапазон дат, большую дробную точность по умолчанию и необязательную точность, указанную пользователем. Также в зависимости от заданной пользователем точности он может использовать меньше памяти.

465 голосов
/ 26 августа 2009

DATETIME2 имеет диапазон дат от «0001/01/01» до «9999/12/31», в то время как тип DATETIME поддерживает только год 1753-9999.

Также, если вам нужно, DATETIME2 может быть более точным с точки зрения времени; DATETIME ограничен 3 1/3 миллисекундами, в то время как DATETIME2 может быть с точностью до 100 нс.

Оба типа сопоставляются с System.DateTime в .NET - без разницы.

Если у вас есть выбор, я бы рекомендовал использовать DATETIME2, когда это возможно. Я не вижу никаких преимуществ при использовании DATETIME (за исключением обратной совместимости) - у вас будет меньше проблем (с датами, выходящими за пределы допустимого диапазона и возникающими из-за этого).

Плюс: если вам нужна только дата (без временной части), используйте DATE - это так же хорошо, как DATETIME2 и экономит ваше пространство! :-) То же самое касается только времени - используйте TIME. Вот для чего существуют эти типы!

187 голосов
/ 11 сентября 2012

datetime2 побеждает в большинстве аспектов, кроме (совместимость старых приложений)

  1. больше диапазон значений
  2. лучше Точность
  3. меньше место для хранения (если указана необязательная точность, указанная пользователем)

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

обратите внимание на следующие пункты

  • Синтаксис
    • datetime2 [(точность долей секунды => выглядит ниже размера хранилища)]
  • Точность, масштаб
    • от 0 до 7 цифр с точностью до 100 нс.
    • Точность по умолчанию составляет 7 цифр.
  • Размер хранилища
    • 6 байтов для точности менее 3;
    • 7 байтов для точности 3 и 4.
    • Все остальные значения точности требуют 8 байтов .
  • DateTime2 (3) имеет то же количество цифр, что и DateTime, но использует 8 байтов вместо 8 байт ( SQLHINTS- DateTime против DateTime2 )
  • Подробнее о datetime2 (статья Transact-SQL MSDN)

источник изображения: MCTS самообучающийся учебный комплект (экзамен 70-432): Microsoft® SQL Server® 2008 - внедрение и обслуживание Глава 3: Таблицы -> Урок 1. Создание таблиц -> стр. 66

104 голосов
/ 08 марта 2012

Я согласен с @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. Неявное округление дат явно вызывает путаницу:

15 голосов
/ 10 июля 2017

Почти все ответы и комментарии были тяжелыми для плюсов и легкими минусами. Вот краткий обзор всех «за» и «против» на данный момент, а также некоторые важные «против» (в # 2 ниже), о которых я только что упоминал, упомянуто или не упоминалось вовсе.

  1. ПЛЮСЫ:

1,1. Больше соответствует ISO (ISO 8601) (хотя я не знаю, как это проявляется на практике).

1.2. Большой диапазон (с 1/1/0001 по 12/31/9999 по сравнению с 1/1 / 1753-12 / 31/9999) (хотя дополнительный диапазон, все до 1753 года, скорее всего, не будет использоваться, кроме как, в исторических, астрономических, геологических и т. д. приложениях).

1.3. Точно соответствует диапазону .NET DateTime Type (хотя оба преобразуются туда и обратно без специального кодирования, если значения находятся в пределах диапазона и точности целевого типа, за исключением Con # 2.1 ниже, иначе произойдет ошибка / округление).

1.4. Более высокая точность (100 наносекунд, то есть 0,000,000,1 сек. Против 3,33 миллисекунды или 0,003,33 сек.) (Хотя дополнительная точность, скорее всего, не будет использоваться, кроме как в инженерных / научных приложениях).

1,5. Когда сконфигурировано для аналогично (поскольку в 1 миллисекунде "не" (как в 3.33 миллисекундах), как утверждал Иман Абиди) точность равна DateTime, использует меньше места (7 против 8 байтов), но затем конечно, вы потеряете прецизионное преимущество, которое, вероятно, является одним из двух (другое - диапазон наиболее часто рекламируемых, хотя, вероятно, ненужных).

  1. CONS:

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. возьмите разницу между двумя датами для расчета «возраста». Примечание: Вы не можете просто использовать функцию DateDiff SQL Server вместо этого, потому что она не вычисляет 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 до DateTime fСначала (и при необходимости вернитесь к DateTime2), но вы потеряете преимущества точности и дальности (все до 1753 года) в размере DateTime2 против DateTime, которые являются 2 крупнейшими и также одинаковыми время наименьшее 2 наименее вероятно, что необходимо, и возникает вопрос, зачем его использовать, когда вы теряете неявные / простые преобразования в числовые с плавающей точкой (количество дней) для сложения / вычитания / «возраста» (против DateDiff) / Avg Выгода от Calcs, которая является большой в моем опыте.

Кстати, Avg даты-времени является (или, по крайней мере, должно быть) важным вариантом использования. а) Помимо использования в получении средней продолжительности, когда дата-время (так как общая базовая дата-время) используются для представления длительности (обычная практика), б) также полезно получить статистику в виде панели мониторинга о том, какая средняя дата- время находится в столбце даты-времени диапазона / группы строк. c) Стандартный (или, по крайней мере, должен быть стандартным) специальный запрос для мониторинга / устранения неисправностей значений в столбце, которые могут быть недействительными никогда / больше и / или могут быть устаревшими, - перечислить для каждого значения счетчик вхождений и (при наличии) Min, Avg и Max отметок даты и времени, связанных с этим значением.

15 голосов
/ 11 сентября 2015

Вот пример, который покажет вам различия в размере хранилища (в байтах) и точности между 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).

15 голосов
/ 13 февраля 2012

DateTime2 наносит ущерб, если вы - разработчик Access, пытающийся написать Now () в соответствующее поле. Просто выполнил миграцию Access -> SQL 2008 R2 и поместил все поля даты и времени в DateTime2. Добавление записи с Now () в качестве значения, полученного в результате взрыва. Это было хорошо 01.01.2012 14:53:04, но не 10.01.2012 14:53:04.

После того, как персонаж сделал разницу. Надеюсь, это кому-нибудь поможет.

9 голосов
/ 26 июня 2014

при увеличении точности с datetime2 , некоторые клиенты не поддерживают date , time или datetime2 и заставит вас преобразовать в строковый литерал. В частности, Microsoft упоминает проблемы ODBC, OLE DB, JDBC и SqlClient «нижнего уровня» с этими типами данных и имеет диаграмму , показывающую, как каждый может сопоставить тип.

Если значение совместимости выше точности, используйте datetime

9 голосов
/ 21 июня 2013

Интерпретация строк даты в 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 будут обрабатываться правильно, независимо от настроек языка / языка.

7 голосов
/ 09 февраля 2018

Старый вопрос ... Но я хочу добавить кое-что, что еще не было сказано кем-то здесь ... (Примечание: это мое собственное наблюдение, поэтому не спрашивайте никаких ссылок)

Datetime2 быстрее при использовании в критериях фильтрации.

TLDR:

В SQL 2016 у меня была таблица с сотнями тысяч строк и столбцом даты-времени 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.

Теперь тот же запрос, который ранее был отключен, занимает менее секунды.

ура

...