it-swarm.com.ru

DateTime2 против DateTime в SQL Server

Который из: 

рекомендуется хранить дату и время в SQL Server 2008+?

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

667
Mikeon

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

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

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

557
Adam Porad

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. Вот для чего существуют эти типы!

454
marc_s

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 (статья о MSDN на Transact-SQL)

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

175
Iman Abidi

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

102
EBarr

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

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

15
Rhett A Brown

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

13
Baodad

Почти все ответы и комментарии были тяжелыми для плюсов и легкими минусами. Вот краткий обзор всех плюсов и минусов на данный момент, а также некоторые важные минусы (в # 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 (хотя оба преобразуются туда и обратно без специального кодирования, если значения находятся в пределах диапазона и точности целевого типа, за исключением Con # 2.1 ниже, иначе произойдет ошибка/округление).

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

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

  1. МИНУСЫ: 

2.1. При передаче параметра в .NET SqlCommand необходимо указать System.Data.SqlDbType.DateTime2, если вы можете передавать значение вне диапазона и/или точности DateTime SQL Server, поскольку по умолчанию используется значение 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'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 выгода calcs, которая является большой в моем опыте.

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

12
Tom

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

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

8
FistOfFury

Интерпретация строк даты в 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 of SET DATEFORMAT, которая гласит: Некоторые форматы символьных строк, например ISO 8601, интерпретируются независимо от настройки DATEFORMAT. Очевидно, не правда!

Пока меня это не укусило, я всегда думал, что даты yyyy-mm-dd будут обрабатываться правильно, независимо от настроек языка/локали.

7
Richard Fawcett

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

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.

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

ура

5
Khan

Согласно этой статье , если вы хотите иметь одинаковую точность DateTime с использованием DateTime2, вы просто должны использовать DateTime2 (3). Это должно дать вам ту же точность, занимать на один байт меньше и обеспечить расширенный диапазон. 

4
jKlaus

Я просто наткнулся на еще одно преимущество для DATETIME2: он позволяет избежать ошибки в модуле Python adodbapi, которая взрывается, если передается значение стандартной библиотеки datetime, которое имеет ненулевые микросекунды для столбца DATETIME, но работает нормально, если столбец определен как DATETIME2.

3
Bob Kline
Select ValidUntil + 1
from Documents

Вышеуказанный SQL не будет работать с полем DateTime2 . Он возвращает ошибку «Тип столкновения операндов: datetime2 несовместим с int»

Добавление 1, чтобы получить следующий день - это то, что разработчики делали с датами годами. Теперь у Microsoft есть супер новое поле datetime2, которое не может справиться с этой простой функциональностью.

«Давайте использовать этот новый тип, который хуже старого», я так не думаю!

0
Paul McCarthy

Я думаю, что DATETIME2 - лучший способ сохранить дату, потому что он имеет большую эффективность, чем DATETIME. В SQL Server 2008 вы можете использовать DATETIME2, он хранит дату и время, занимает 6-8 байт для хранения и имеет точность 100 наносекунд. Так что любой, кому нужна большая точность времени, захочет DATETIME2.

0
James