Будет ли GETUTCDATE() возвращать одно и то же значение, если оно используется дважды в одном выражении?
У меня есть триггер, который автоматически устанавливает CreationDate и ModifiedDate из данной записи в текущее время UTC всякий раз, когда вводится значение. (CreationDate останется таким же после этого, а ModifiedDate будет обновляться при каждом обновлении через другой триггер).
Я хочу убедиться, что вставляемые и никогда обновленные элементы будут иметь точно такое же значение для CreationDate и ModifiedDate, поэтому я использовал переменную вроде этого:
DECLARE @currentTime DATETIME
SELECT @currentTime = GETUTCDATE()
UPDATE dbo.MyTable SET CreationDate = @currentTime, ModifiedDate = @currentTime
...
В моем менталитете ментального программирования я предполагаю, что это предотвращает вызов GETUTCDATE()
из двух раз и потенциально дает несколько разные результаты. Это действительно необходимо? Если нет, было бы это дороже, дешевле или точно так же, как в следующем коде?
UPDATE dbo.MyTable SET CreationDate = GETUTCDATE(), ModifiedDate = GETUTCDATE()
...
Ответы
Ответ 1
DECLARE @Counter INT = 1
WHILE (1 = (SELECT 1 WHERE GETUTCDATE() = GETUTCDATE()))
SET @Counter = @Counter+1
SELECT @Counter /*Returns almost immediately with a number in the 000s for me.*/
И только для того, чтобы это произошло, также в списке SELECT
.
DECLARE @T TABLE
(
rownum INT IDENTITY(1,1) PRIMARY KEY,
d1 datetime,
d2 datetime
)
WHILE (NOT EXISTS(SELECT * FROM @T WHERE d1 <> d2))
BEGIN
DELETE FROM @T
INSERT INTO @T
SELECT GETUTCDATE(),GETUTCDATE()
END
SELECT * FROM @T
BTW: ЕСЛИ по какой-то причине вы хотите оценить GETUTCDATE()
для каждой строки, вы можете обернуть ее в скалярный UDF.
CREATE FUNCTION dbo.GETUTCDATE()
RETURNS DATETIME
WITH SCHEMABINDING
AS
BEGIN
RETURN GETUTCDATE()
END
GO
SELECT GETUTCDATE(),dbo.GETUTCDATE()
FROM master..spt_values
Ответ 2
Благодаря ссылкам, предоставленным gbn, я верю, что отвечает на мой вопрос:
Совсем с rand() Он оценивается один раз за столбец, но после его оценки остается неизменным для всех строк.... посмотрите на свойства оператора ComputeScalar в фактическом плане выполнения, вы увидите, что GetDate() оценивается дважды.
Я проверил, и похоже, что это все равно происходит в SQL Server 2008: GetUtcDate()
дважды оценивается в плане выполнения. Он не будет производить разные результаты для каждой строки, но вполне возможно, что он может привести к другому результату на один столбец, если синхронизация закончится именно так.
Изменить
Я могу доказать это! Попробуйте следующее:
select GETUTCDATE(), RAND(), RAND(), ...[~3000 RAND()s]..., RAND(), GETUTCDATE()
from [TableOfYourChoice]
В моем эксперименте я закончил с 2011-05-17 20:47:34.247
в первом столбце и 2011-05-17 20:47:34.250
в последнем столбце, показывая разницу в три миллисекунды в результате оценки всего RAND()
между первым и вторым вызывает GETUTCDATE().
Ответ 3
Это будет одно и то же значение.
GETDATE и GETUTCDATE - некоторые из функций, которые оцениваются один раз для каждого запроса: не для каждой строки или столбца в этом запросе. Оптимизатор гарантирует, что они будут одинаковыми, поскольку он одновременно обновляет значения.
Другой вариант - определить ограничения DEFAULT, чтобы вы могли сделать это и меньше беспокоиться об этом.
UPDATE dbo.MyTable
SET CreationDate = DEFAULT, ModifiedDate = DEFAULT, ...
...
У меня есть таблицы с похожими столбцами с ограничениями DEFAULT и никогда не возникало проблем. Это также означает, что мне никогда не нужно думать о том, какую функцию я использую в коде.
Edit:
Я мог ошибаться: SQL Server: заинтригован GETDATE()
Или я мог бы быть прав: Выбор функции GETDATE() дважды в списке выбора - то же значение для обоих?
Статья: Конор Куннигам упоминает это поведение
Edit2: Я демонстративно ошибаюсь: см. сам ответ StriplingWarrior. Он оценивался за столбец (не за строку, а не за запрос)
Ответ 4
Сохранение GETUTCDATE() в переменной является лучшим вариантом, поскольку он гарантирует, что CreationDate и ModifiedDate остаются такими же. Тем не менее, я назвал GETUTCDATE()
количество времени на запрос, и все они вернули одно и то же значение, поэтому мне кажется, что значение GETUTCDATE() остается таким же для каждого запроса.
Ответ 5
Основываясь на обширных экспериментах в SQL Server 2008, я считаю, что следующая характеристика правильная:
В одном запросе SELECT, INSERT или UPDATE каждое появление функции даты и времени возвращает одно и то же значение везде, где оно отображается во всех строках и столбцах, включая значения по умолчанию столбца.
Две разные функции даты и времени (например, GETUTCDATE() и GETDATE()) могут возвращать разные времена друг от друга (даже после настройки для часовых поясов или любого другого).
Несколько запросов в одной партии могут возвращать разные значения.
SELECT GETUTCDATE(), GETUTCDATE() -- These will be the same
SELECT GETUTCDATE() -- These may
SELECT GETUTCDATE() -- be different
Это поведение не документировано нигде, и использование переменной делает намерение ясным, поэтому я, вероятно, не буду полагаться на это поведение, если не избежать этой зависимости, является основным бременем.