Eu tenho um gatilho que define automaticamente o CreationDate e ModifiedDate da input dada para a hora UTC atual sempre que um valor é inserido. (CreationDate permanecerá o mesmo depois disso, enquanto ModifiedDate será atualizado em cada atualização através de outro trigger).
Eu quero ter certeza de que os itens inseridos e nunca atualizados terão exatamente o mesmo valor para CreationDate e ModifiedDate, então usei uma variável como esta:
DECLARE @currentTime DATETIME SELECT @currentTime = GETUTCDATE() UPDATE dbo.MyTable SET CreationDate = @currentTime, ModifiedDate = @currentTime ...
Na minha mentalidade de programação imperativa, GETUTCDATE()
que isso evite que GETUTCDATE()
seja chamado duas vezes e, potencialmente, produza resultados ligeiramente diferentes. Isso é realmente necessário? Se não, isso seria mais caro, menos caro, ou exatamente o mesmo que o código a seguir?
UPDATE dbo.MyTable SET CreationDate = GETUTCDATE(), ModifiedDate = GETUTCDATE() ...
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.*/
E só para provar isso acontece quando na lista SELECT
também.
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: SE, por algum motivo, você quiser avaliar GETUTCDATE()
por linha, poderá agrupá-lo em uma UDF escalar.
CREATE FUNCTION dbo.GETUTCDATE() RETURNS DATETIME WITH SCHEMABINDING AS BEGIN RETURN GETUTCDATE() END GO SELECT GETUTCDATE(),dbo.GETUTCDATE() FROM master..spt_values
Graças aos links fornecidos pelo gbn, acredito que isso responde à minha pergunta :
Em comum com rand () é avaliado uma vez por coluna, mas uma vez avaliado permanece o mesmo para todas as linhas. … observe as propriedades do operador ComputeScalar no plano de execução real e você verá que GetDate () é avaliado duas vezes.
Eu verifiquei, e parece que isso ainda acontece da mesma maneira no SQL Server 2008: GetUtcDate()
é avaliado duas vezes no plano de execução. Ele não produzirá resultados diferentes por linha, mas é possível que ele produza um resultado diferente por coluna se o tempo acabar bem.
Eu posso realmente provar esse comportamento! Tente isto:
select GETUTCDATE(), RAND(), RAND(), ...[~3000 RAND()s]..., RAND(), GETUTCDATE() from [TableOfYourChoice]
Na minha experiência, terminei com 2011-05-17 20:47:34.247
na primeira coluna e 2011-05-17 20:47:34.250
na coluna final, mostrando uma diferença de três milissegundos como resultado da avaliação de todos os RAND()
s entre a primeira e segunda chamadas para GETUTCDATE ().
Será o mesmo valor.
GETDATE e GETUTCDATE são algumas das funções avaliadas uma vez por consulta: não por linha ou coluna nessa consulta. O otimizador garantirá que eles sejam os mesmos, porque atualiza os valores ao mesmo tempo
Outra opção é definir as restrições DEFAULT para que você possa fazer isso e se preocupar menos com isso.
UPDATE dbo.MyTable SET CreationDate = DEFAULT, ModifiedDate = DEFAULT, ... ...
Eu tenho tabelas com colunas semelhantes com restrições padrão e nunca tive um problema. Isso também significa que nunca preciso pensar em qual function eu uso no código.
Editar:
Eu posso estar errado: SQL Server: intrigado com GETDATE ()
Ou eu poderia estar certo: Selecionando a function GETDATE () duas vezes em uma lista de seleção – mesmo valor para ambos?
Artigo: Conor Cunnigham menciona o comportamento
Edit2: Eu sou demonstrativamente errado: veja a auto resposta de StriplingWarrior. É avaliado por coluna (não por linha e não por consulta)
Manter o GETUTCDATE () em uma variável é uma opção melhor, pois garante que CreationDate e ModifiedDate permaneçam iguais. No entanto, eu chamei GETUTCDATE()
número de tempo por consulta e todos eles retornaram o mesmo valor, então para mim parece que o valor GETUTCDATE () permanece igual por consulta.
Com base em extensos experimentos no SQL Server 2008, acredito que a seguinte caracterização está correta:
Em uma única consulta SELECT, INSERT ou UPDATE, cada aparência de uma function de data e hora retornará o mesmo valor em todos os lugares em todas as linhas e colunas, incluindo os valores padrão da coluna.
Duas funções diferentes de data e hora (por exemplo, GETUTCDATE () e GETDATE ()) podem retornar diferentes tempos umas das outras (mesmo após o ajuste para fusos horários ou qualquer outro).
Várias consultas em um único lote podem retornar valores diferentes.
SELECT GETUTCDATE(), GETUTCDATE() -- These will be the same SELECT GETUTCDATE() -- These may SELECT GETUTCDATE() -- be different
Esse comportamento não é documentado em nenhum lugar, e o uso de uma variável torna a intenção clara, então eu provavelmente não confiaria nesse comportamento, a menos que evitar essa dependência seja um grande fardo.