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 в большинстве аспектов, кроме (совместимость старых приложений)

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

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

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

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


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

  1. плюсы:

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" в Day0 (дней).

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.