AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 175695
Accepted
Riley Major
Riley Major
Asked: 2017-06-08 09:24:01 +0800 CST2017-06-08 09:24:01 +0800 CST 2017-06-08 09:24:01 +0800 CST

Por que GETUTCDATE é anterior a SYSDATETIMEOFFSET?

  • 772

Como alternativa, como a Microsoft tornou possível a viagem no tempo?

Considere este código:

DECLARE @Offset datetimeoffset = sysdatetimeoffset();
DECLARE @UTC datetime = getUTCdate();
DECLARE @UTCFromOffset datetime = CONVERT(datetime,SWITCHOFFSET(@Offset,0));
SELECT
    Offset = @Offset,
    UTC = @UTC,
    UTCFromOffset = @UTCFromOffset,
    TimeTravelPossible = CASE WHEN @UTC < @UTCFromOffset THEN 1 ELSE 0 END;

@Offseté definido antes @UTC de , mas às vezes tem um valor posterior . (Eu tentei isso no SQL Server 2008 R2 e no SQL Server 2016. Você precisa executá-lo algumas vezes para capturar as ocorrências suspeitas.)

Isso não parece ser simplesmente uma questão de arredondamento ou falta de precisão. (Na verdade, acho que o arredondamento é o que "conserta" o problema ocasionalmente.) Os valores para uma execução de amostra são os seguintes:

  • Desvio
    • 07-06-2017 12:01:58.8801139 -05:00
  • UTC
    • 07-06-2017 17:01:58.877
  • UTC do deslocamento:
    • 07-06-2017 17:01:58.880

Portanto, a precisão de data e hora permite o .880 como um valor válido.

Mesmo os exemplos GETUTCDATE da Microsoft mostram os valores SYS* sendo posteriores aos métodos mais antigos, apesar de terem sido SELECTed antes :

SELECT 'SYSDATETIME()      ', SYSDATETIME();  
SELECT 'SYSDATETIMEOFFSET()', SYSDATETIMEOFFSET();  
SELECT 'SYSUTCDATETIME()   ', SYSUTCDATETIME();  
SELECT 'CURRENT_TIMESTAMP  ', CURRENT_TIMESTAMP;  
SELECT 'GETDATE()          ', GETDATE();  
SELECT 'GETUTCDATE()       ', GETUTCDATE();  
/* Returned:  
SYSDATETIME()            2007-05-03 18:34:11.9351421  
SYSDATETIMEOFFSET()      2007-05-03 18:34:11.9351421 -07:00  
SYSUTCDATETIME()         2007-05-04 01:34:11.9351421  
CURRENT_TIMESTAMP        2007-05-03 18:34:11.933  
GETDATE()                2007-05-03 18:34:11.933  
GETUTCDATE()             2007-05-04 01:34:11.933  
*/

Presumo que isso seja porque eles vêm de diferentes informações do sistema subjacente. Alguém pode confirmar e dar detalhes?

A documentação SYSDATETIMEOFFSET da Microsoft diz que "o SQL Server obtém os valores de data e hora usando a API do Windows GetSystemTimeAsFileTime()" (obrigado srutzky), mas sua documentação GETUTCDATE é muito menos específica, dizendo apenas que o "valor é derivado do sistema operacional do computador no qual a instância do SQL Server está sendo executada".

(Isso não é totalmente acadêmico. Encontrei um pequeno problema causado por isso. Eu estava atualizando alguns procedimentos para usar SYSDATETIMEOFFSET em vez de GETUTCDATE, na esperança de maior precisão no futuro, mas comecei a obter pedidos estranhos porque outros procedimentos foram ainda usando GETUTCDATE e ocasionalmente "saltando à frente" dos meus procedimentos convertidos nos logs.)

sql-server datetime
  • 1 1 respostas
  • 4038 Views

1 respostas

  • Voted
  1. Best Answer
    Solomon Rutzky
    2017-06-08T13:47:32+08:002017-06-08T13:47:32+08:00

    O problema é uma combinação de granularidade/precisão de tipo de dados e origem dos valores.

    Primeiro, DATETIMEé apenas preciso/granular a cada 3 milissegundos. Portanto, converter de um tipo de dados mais preciso, como DATETIMEOFFSETou DATETIME2não apenas arredondar para cima ou para baixo para o milissegundo mais próximo, pode ser 2 milissegundos diferente.

    Em segundo lugar, a documentação parece implicar uma diferença de onde os valores vêm. As funções SYS* usam as funções FileTime de alta precisão.

    A documentação do SYSDATETIMEOFFSET afirma:

    O SQL Server obtém os valores de data e hora usando a API do Windows GetSystemTimeAsFileTime().

    enquanto a documentação GETUTCDATE afirma:

    Esse valor é derivado do sistema operacional do computador no qual a instância do SQL Server está sendo executada.

    Em seguida, na documentação About Time , um gráfico mostra os dois (entre vários) tipos a seguir:

    • System Time = "Ano, mês, dia, hora, segundo e milissegundo, obtidos do relógio interno do hardware."
    • File Time = "O número de intervalos de 100 nanossegundos desde 1º de janeiro de 1601."

    Pistas adicionais estão na documentação .NET para a StopWatchclasse (ênfase em negrito itálico minha):

    • Classe de cronômetro

      O cronômetro mede o tempo decorrido contando os tiques do cronômetro no mecanismo de cronômetro subjacente. Se o hardware e o sistema operacional instalados oferecerem suporte a um contador de desempenho de alta resolução, a classe Stopwatch usará esse contador para medir o tempo decorrido. Caso contrário, a classe Stopwatch usa o cronômetro do sistema para medir o tempo decorrido.

    • Campo Cronômetro.IsHighResolution

      O temporizador usado pela classe Stopwatch depende do hardware do sistema e do sistema operacional. IsHighResolution é true se o cronômetro do cronômetro for baseado em um contador de desempenho de alta resolução. Caso contrário, IsHighResolution é false , o que indica que o cronômetro do Stopwatch é baseado no cronômetro do sistema .

    Portanto, existem diferentes "tipos" de tempos que têm diferentes precisões e diferentes fontes.

    Mas, mesmo que seja uma lógica muito vaga, testar os dois tipos de funções como fontes para o DATETIMEvalor prova isso. A seguinte adaptação da consulta da pergunta mostra esse comportamento:

    DECLARE @Offset DATETIMEOFFSET = SYSDATETIMEOFFSET(),
            @UTC2 DATETIME = SYSUTCDATETIME(),
            @UTC DATETIME = GETUTCDATE();
    DECLARE @UTCFromOffset DATETIME = CONVERT(DATETIME, SWITCHOFFSET(@Offset, 0));
    SELECT
        Offset = @Offset,
        UTC2 = @UTC2,
        UTC = @UTC,
        UTCFromOffset = @UTCFromOffset,
        TimeTravelPossible = CASE WHEN @UTC < @UTCFromOffset THEN 1 ELSE 0 END,
        TimeTravelPossible2 = CASE WHEN @UTC2 < @UTCFromOffset THEN 1 ELSE 0 END;
    

    Devoluções:

    Offset                 2017-06-07 17:50:49.6729691 -04:00
    UTC2                   2017-06-07 21:50:49.673
    UTC                    2017-06-07 21:50:49.670
    UTCFromOffset          2017-06-07 21:50:49.673
    TimeTravelPossible     1
    TimeTravelPossible2    0
    

    Como você pode ver nos resultados acima, UTC e UTC2 são ambos DATETIMEtipos de dados. @UTC2é definido via SYSUTCDATETIME()e é definido após @Offset(também obtido de uma função SYS*), mas antes do @UTCqual é definido via GETUTCDATE(). No entanto, @UTC2parece vir antes @UTC. A parte OFFSET disso não tem relação com nada.

    NO ENTANTO, para ser justo, isso ainda não é uma prova em sentido estrito. @MartinSmith rastreou a GETUTCDATE()chamada e encontrou o seguinte:

    insira a descrição da imagem aqui

    Eu vejo três coisas interessantes nesta pilha de chamadas:

    1. Is começa com uma chamada para a GetSystemTime()qual retorna um valor que é preciso apenas em milissegundos.
    2. Ele usa DateFromParts (ou seja, nenhuma fórmula para converter, apenas use as peças individuais).
    3. Há uma chamada para QueryPerformanceCounter na parte inferior. Este é um contador de diferenças de alta resolução que pode estar sendo usado como meio de "correção". Eu vi algumas sugestões de usar um tipo para ajustar o outro ao longo do tempo à medida que intervalos longos ficam lentamente fora de sincronia (consulte Como obter carimbo de data/hora da precisão de tique em .NET / C#? no SO). Isso não aparece ao ligar SYSDATETIMEOFFSET.

    Há muitas informações boas aqui sobre os diferentes tipos de tempo, fontes diferentes, desvio, etc: Adquirir carimbos de tempo de alta resolução .

    Realmente, não é apropriado comparar valores de diferentes precisões. Por exemplo, se você tem 2017-06-07 12:01:58.8770011e 2017-06-07 12:01:58.877, como você sabe que aquele com menos precisão é maior, menor ou igual ao valor com mais precisão? Compará-los pressupõe que o menos preciso é realmente 2017-06-07 12:01:58.8770000, mas quem sabe se isso é verdade ou não? O tempo real poderia ter sido 2017-06-07 12:01:58.8770005ou 2017-06-07 12:01:58.8770111.

    No entanto, se você tiver DATETIMEtipos de dados, deverá usar as funções SYS* como fonte, pois elas são mais precisas, mesmo se você perder alguma precisão, pois o valor é forçado a um tipo menos preciso. E nesse sentido, parece fazer mais sentido usar SYSUTCDATETIME()em vez de chamar SYSDATETIMEOFFSET()apenas para ajustá-lo via SWITCHOFFSET(@Offset, 0).

    • 9

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve