Почему Datediff между GETDATE() и SYSDATETIME() в миллисекундах всегда отличается?

Я пытаюсь получить Datediff между GETDATE() и SYSDATETIME() в миллисекундах.

SELECT DATEDIFF(ms, GETDATE() , SYSDATETIME());        

В результате я получаю 0 или 1 или 2 или 3. В чем причина этой разницы?

Посмотрите эту скрипту.


person Himanshu Jansari    schedule 18.08.2012    source источник
comment
Что возвращает SELECT DATEDIFF(ms, GETDATE(), GETDATE());?   -  person Waleed Khan    schedule 18.08.2012
comment
Движок может быть достаточно умен, чтобы кэшировать два идентичных выражения.   -  person McGarnagle    schedule 18.08.2012
comment
Потому что две функции не могут быть вызваны одновременно (в одно и то же время). Другие запущенные процессы могут повлиять на тайминги. Есть десятки причин, по которым они могут отличаться на разную величину. Зачем вам это нужно, просто из любопытства?   -  person Ken White    schedule 18.08.2012
comment
@KenWhite Если мы выполним SELECT DATEDIFF(ms, GETDATE(), GETDATE()), будет ли GetDate() выполняться дважды или один раз?   -  person Himanshu Jansari    schedule 18.08.2012
comment
Скорее всего один раз, потому что СУБД достаточно умна, чтобы понять, что вы вызываете одну и ту же функцию. Однако вы этого не делаете — вы вызываете две разные функции, которые выполняют два разных пути кода.   -  person Ken White    schedule 18.08.2012
comment
@KenWhite, ты прав. СУБД не выполняет одну и ту же функцию дважды. Посмотрите эту скрипту. Результат второго запроса всегда 0.   -  person Himanshu Jansari    schedule 18.08.2012
comment
@hims056 - Это не всегда ноль. Просто скорее всего будет ноль.   -  person Martin Smith    schedule 18.08.2012
comment
@Даунвотер. Ваш отзыв пожалуйста....   -  person Himanshu Jansari    schedule 11.12.2012
comment
@ hims056 в будущем, пожалуйста, имейте в виду, что не всегда сложно выяснить, кто проводит неоправданное голосование против ...   -  person Aaron Bertrand    schedule 29.01.2013


Ответы (3)


Это два разных вызова функций, которые могут возвращаться два раза в разное время.

Кроме того, GETDATE возвращает тип данных datetime с точностью всего 3-4 мс, тогда как SYSDATETIME() возвращает тип данных datetime2(7).

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

DECLARE @D1 DATETIME2 = '2012-08-18 10:08:40.0650000'
DECLARE @D2 DATETIME = @D1 /*Rounded to 2012-08-18 10:08:40.067*/
SELECT DATEDIFF(ms, @D1 , @D2) /*Returns 2*/

Другой ответ неверен: если вы подставите GETDATE(), функция будет вызываться только один раз, как показано ниже.

WHILE DATEDIFF(ms, GETDATE() , GETDATE()) = 0 
PRINT 'This will not run in an infinite loop'

При запуске цикла на моем рабочем столе Windows XP с GETDATE() и SYSDATETIME я также вижу результаты, указывающие на то, что может происходить что-то еще. Возможно, вызов другого API.

CREATE TABLE #DT2
  (
     [D1] [DATETIME2](7),
     [D2] [DATETIME2](7)
  )

GO

INSERT INTO #DT2
VALUES(Getdate(), Sysdatetime())

GO 100

SELECT DISTINCT [D1],
                [D2],
                Datediff(MS, [D1], [D2]) AS MS
FROM   #DT2

DROP TABLE #DT2 

Пример результатов ниже

+-----------------------------+-----------------------------+-----+
|             D1              |             D2              | MS  |
+-----------------------------+-----------------------------+-----+
| 2012-08-18 10:16:03.2500000 | 2012-08-18 10:16:03.2501680 |   0 |
| 2012-08-18 10:16:03.2530000 | 2012-08-18 10:16:03.2501680 |  -3 |
| 2012-08-18 10:16:03.2570000 | 2012-08-18 10:16:03.2501680 |  -7 |
| 2012-08-18 10:16:03.2600000 | 2012-08-18 10:16:03.2501680 | -10 |
| 2012-08-18 10:16:03.2630000 | 2012-08-18 10:16:03.2501680 | -13 |
| 2012-08-18 10:16:03.2630000 | 2012-08-18 10:16:03.2657914 |   2 |
| 2012-08-18 10:16:03.2670000 | 2012-08-18 10:16:03.2657914 |  -2 |
| 2012-08-18 10:16:03.2700000 | 2012-08-18 10:16:03.2657914 |  -5 |
| 2012-08-18 10:16:03.2730000 | 2012-08-18 10:16:03.2657914 |  -8 |
| 2012-08-18 10:16:03.2770000 | 2012-08-18 10:16:03.2657914 | -12 |
| 2012-08-18 10:16:03.2800000 | 2012-08-18 10:16:03.2814148 |   1 |
+-----------------------------+-----------------------------+-----+

Интересующие строки

| 2012-08-18 10:16:03.2600000 | 2012-08-18 10:16:03.2501680 | -10 |
| 2012-08-18 10:16:03.2630000 | 2012-08-18 10:16:03.2501680 | -13 |

Это несоответствие слишком велико, чтобы быть проблемой округления, и не может быть просто проблемой синхронизации с задержкой между вызовом двух функций, поскольку проблема существует более чем в одной строке, которая GETDATE сообщает 10:16:03.26X, тогда как SYSDATETIME сообщает 10:16:03.250

person Martin Smith    schedule 18.08.2012
comment
Также кажется, что функции используют другую точность, так как в D1 последние четыре цифры всегда равны нулю. Это не так для D2, где все семь цифр кажутся значащими. - person apaderno; 19.08.2012
comment
@kiamlaluno - Да. Тип данных datetime имеет точность только 300 тиков в секунду. то есть до 3 цифр точности с последней цифрой 0, 3 или 7. Более новый тип данных datetime2 может представлять до 7 десятичных цифр точности. - person Martin Smith; 19.08.2012

Они отличаются тем, что две функции не могут быть вызваны одновременно (в одно и то же время). Другие запущенные процессы могут повлиять на тайминги. Есть десятки причин, по которым они могут отличаться на разную величину.

Если вы сделаете то же самое с двумя вызовами GetDate() вместо этого, они не приведут к никакой разнице, потому что механизм базы данных достаточно умен, чтобы понять, что это одно и то же, и повторно использовать результаты. Однако использование GetDate() и SysDateTime() отличается, потому что это не один и тот же путь кода (они делают разные вещи).

Подумайте об этом так: если вы видите 1 + 2 и 1 + 2, легко увидеть, что первое выражение и второе совпадают, и поэтому вам нужно выполнить вычисление только один раз. Если вы измените его на 1 + Rand() и 1 + Rand(), вы не сможете узнать, что вернут два разных вызова Rand(), поэтому вам придется выполнять вычисления отдельно.

person Ken White    schedule 18.08.2012
comment
Этот ответ вводит в заблуждение. Даже если бы две функции могли быть вызваны одновременно, результаты (с точностью до миллисекунды) часто/обычно различались бы. И действительно, более ранний вызов GETDATE() может вернуть время позже, чем последующий SYSDATETIME(), и наоборот. - person brewmanz; 06.02.2017
comment
@brewmanz: Как это вводит в заблуждение? Там точно сказано, что они никогда не приведут к тем же результатам. Вы прочитали первое предложение и остановились? - person Ken White; 06.02.2017
comment
Несколько вводящих в заблуждение причин: A) Они МОГУТ давать одинаковые результаты, и я могу предсказать, когда такие случаи будут B) Когда результаты различаются, это НЕ потому, что две функции нельзя вызывать одновременно C) Это НЕ то же самое, что использовать Rand (); результат является детерминированным, и, учитывая результат SysDateTime(), у меня есть хорошие шансы предсказать, каким будет результат соседнего вызова GetDate(). - person brewmanz; 08.02.2017

Эта разница является хорошим примером разницы между ТОЧНОСТЬЮ и РАЗРЕШЕНИЕМ (на данный момент оставим ТОЧНОСТЬ в стороне). GETDATE() возвращает DATETIME с (очевидно) ТОЧНОСТЬЮ до миллисекунды, но, если вы поместите его в плотный цикл, вы обнаружите, что следующее возвращаемое значение будет через несколько миллисекунд; он может возвращать только около 300 различных значений каждую секунду, так как его РАЗРЕШЕНИЕ составляет всего около 3 или 4 миллисекунд. подробнее об этом читайте здесь Это конструктивная особенность/компромисс типа данных DATETIME.

person brewmanz    schedule 06.02.2017