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 / 166370
Accepted
Marcus Junius Brutus
Marcus Junius Brutus
Asked: 2017-03-07 11:31:56 +0800 CST2017-03-07 11:31:56 +0800 CST 2017-03-07 11:31:56 +0800 CST

segundos fracionários de data e hora

  • 772

Estou lendo a descrição do datetimetipo de dados da documentação do Sybase ASE 15.7 :

As colunas datetime contêm datas entre 1º de janeiro de 1753 e 31 de dezembro de 9999. Os valores de datetime têm precisão de 1/300 segundo em plataformas que oferecem suporte a esse nível de granularidade.

Achei o acima muito confuso. Em primeiro lugar, este é o único tipo de dados para o qual é adicionada a advertência "em plataformas que suportam este nível de granularidade". O que exatamente isso significa e como descubro se minha plataforma é uma daquelas que "suporta esse nível de granularidade"?

Além disso, não está claro para mim o que significa efetivamente armazenar com precisão 1/300 de segundo. Estou acessando o banco de dados usando JDBC para o qual o único tipo plausível é java.sql.Timestamp . Esse tipo me permite recuperar com precisão de nanossegundos. Mas dado que a divisão por 300 requer dígitos infinitos no sistema decimal no caso geral, efetivamente um número fracionário de nanossegundos (com dígitos decimais infinitos) é necessário para manter um valor expresso como 1/300 de segundo. Portanto, isso significa que não consigo obter o valor armazenado no servidor sem perder alguma precisão, por mais insignificante que seja.

Por fim, quando executo a seguinte consulta:

SELECT convert(char(32), submission_date, 139) FROM some..table

Vejo valores como os seguintes:

Jan  6 2014 12:36:12.420000     
Sep 12 2013 13:44:57.100000     
Sep 10 2014 13:47:02.240000     
Sep 10 2014 13:47:07.850000     
Sep 10 2014 13:47:13.346000     
Sep 10 2014 13:47:19.033000     
Sep 10 2014 13:47:24.533000     
Sep 10 2014 13:47:30.030000     
Sep 10 2014 13:47:35.636000     
Sep 10 2014 13:47:41.136000     
Sep 10 2014 13:47:46.750000     
Sep 10 2014 13:47:52.240000     
Sep 25 2014 09:01:18.426000     

Esses valores parecem indicar que apenas milésimos de segundo inteiros são mantidos (não 1/300 de segundo - o que exigiria um número fracionário de milésimos). Se fosse o caso de o servidor armazenar internamente os valores "com precisão de 1/300 segundo", eu esperaria que a conversão para uma notação decimal usasse todas as casas decimais disponíveis (exceto para os casos de borda de 3/300 segundos, 30/300 segundos, 150/300 segundos e alguns outros que não requerem uma quantidade infinita de dígitos no sistema decimal).

sybase jdbc
  • 2 2 respostas
  • 5260 Views

2 respostas

  • Voted
  1. Best Answer
    Hannah Vernon
    2017-03-07T13:14:26+08:002017-03-07T13:14:26+08:00

    datetimeno Adaptive Server Enterprise (e no SQL Server, pois compartilham uma base de código comum que inclui o tipo datetime) é armazenado usando 8 bytes. 4 bytes para a data e 4 bytes para a hora. Você pode ver isso observando a versão binária de um datetime:

    SELECT CONVERT(varbinary(8), CONVERT(datetime, '1753-01-01T00:00:00.000'), 0)
    SELECT CONVERT(varbinary(8), CONVERT(datetime, '1900-01-01T00:00:00.000'), 0)
    SELECT CONVERT(varbinary(8), CONVERT(datetime, '1900-01-02T00:00:00.000'), 0)
    SELECT CONVERT(varbinary(8), CONVERT(datetime, '3000-12-31T23:59:59.997'), 0)
    

    Os quatro valores binários são:

    0xFFFF2E4600000000
    0x0000000000000000
    0x0000000100000000
    0x000622D3018B81FF

    Veja o seguinte, que mostra onde o 1/300 de segundo entra em jogo:

    SELECT CONVERT(varbinary(8), CONVERT(datetime, '1900-01-01T00:00:00.000'), 0) 
    SELECT CONVERT(varbinary(8), CONVERT(datetime, '1900-01-02T00:00:00.000'), 0) 
    SELECT CONVERT(varbinary(8), CONVERT(datetime, '1900-01-02T00:00:00.003'), 0) 
    

    A diferença entre o 2º e o 3º valores, é uma:

    0x0000000000000000
    0x0000000100000000
    0x0000000100000001

    Assim, as datas são armazenadas nos 4 bytes mais significativos; e os tempos são armazenados nos 4 bytes menos significativos. Embora mover para uma precisão maior que 3 milissegundos (1/300 de segundo) seja possível em 4 bytes de armazenamento; essa é toda a precisão que é realmente usada.

    No SQL Server, você pode usar um datetime2(7)tipo de dados para obter precisão de até 7 dígitos, com precisão de 100ns:

    SELECT CONVERT(varbinary(16), CONVERT(datetime2(7), '1900-01-01T00:00:00.0000000'), 0)
    SELECT CONVERT(varbinary(16), CONVERT(datetime2(7), '1900-01-01T00:00:00.0000001'), 0)
    SELECT CONVERT(varbinary(16), CONVERT(datetime2(7), '1900-01-01T00:00:00.0000002'), 0)
    

    O armazenamento desses valores é um pouco diferente, mas você ainda pode ver o valor binário aumentando:

    0x0700000000005B950A
    0x0701000000005B950A
    0x0702000000005B950A

    Estou usando o cliente Sybase ISQL; Utilitário Sybase CTISQL/15.7/P-EBF20996 SP100/DRV.15.7.0.10

    datetimeComo um aparte, existe uma pequena diferença entre os valores de arredondamento do Adaptive Server Enterprise (ASE) e do SQL Server . No SQL Server, milissegundos são arredondados para 0.000,0.003 e 0.007, enquanto no ASE eles são arredondados para 0.000, 0.003e 0.006- por que há uma diferença não está documentada até onde eu sei. Você pode ver isso no ASE executando esta consulta:

    SELECT CONVERT(varchar(50), CONVERT(datetime, N'2017-01-01T23:59:59.997'), 139);
    

    Que retorna:

    Jan  1 2017 23:59:59.996000
    

    Enquanto no SQL Server, o código equivalente,SELECT CONVERT(varchar(50), CONVERT(datetime, N'2017-01-01T23:59:59.997'), 109); , retorna:

    Jan  1 2017 11:59:59:997PM
    
    • 7
  2. Marcus Junius Brutus
    2017-03-07T15:14:38+08:002017-03-07T15:14:38+08:00

    Com base nessa resposta , fica claro que a codificação exata é opaca e contra-intuitiva. Também está claro que a declaração na documentação do Sybase no sentido de que datetimepode conter valores accurate to 1/300 secondé enganosa e imprecisa.

    O que a documentação deveria ter dito é que datetimetem uma resolução/precisão/granularidade (escolha seu termo favorito) de aproximadamente 1/300 de segundo ou aproximadamente 3 ms .

    Fiz um teste para confirmar isso. Em uma mesa com aproximadamente 1000datetime valores (gerados aleatoriamente, pois dependem da entrada do usuário), eu queria ver quantos valores distintos de milissegundos eu encontraria:

     SELECT COUNT(*) FROM
     (
       SELECT DISTINCT y.millis FROM
       (
          SELECT RIGHT(RTRIM(LTRIM(x.submissionDate)), 6) AS millis FROM (
             SELECT convert(char(32), submission_date, 139) AS submissionDate FROM someTable
          ) x
       ) y
     ) z
    

    A instrução SQL mais interna na consulta acima também foi usada na minha pergunta e produz os valores que publiquei na minha pergunta.

    O resultado da consulta composta foi 237, o que é consistente com o acima.

    Além disso, a documentação do SQL Server (que é aplicável, pois a datetimeimplementação faz parte da base de código compartilhada entre o Sybase ASE e o SQL Server), diz o seguinte:


    Segue imagem:

    insira a descrição da imagem aqui


    Na mesma página é ainda assinalado que:

    datetime não é compatível com ANSI ou ISO 8601.

    No geral, acho que usar um tipo tão peludo é um antipadrão. Não consigo entender por que alguém simplesmente não usaria um INTpara armazenar segundos desde a Epoch (sim, eu sei sobre 2038), ou a BIGINTpara armazenar milissegundos ou mesmo microssegundos ou nanossegundos desde a Epoch.


    atualização após testes exaustivos

    Consegui encontrar algum tempo para fazer testes exaustivos sobre esse assunto e consegui chegar ao fundo disso. Aqui estão minhas descobertas (testadas em relação ao Sybase ASE 15.7, acho que os mesmos resultados se aplicam ao SQL Server):

    Provei experimentalmente que o servidor mantém Datetimevalores fornecidos a ele pelo cliente com resolução de 1/300 de segundo. Criei uma tabela com o seguinte DDL:

    DROP TABLE DatetimeTest;
    CREATE TABLE DatetimeTest (
        d DATETIME NOT NULL
    );
    

    … e preenchê-lo (usando um programa de driver em Java) com 1000 valores com incrementos de milissegundos de 1/1000 de segundo. Executando a seguinte consulta:

     SELECT COUNT(*) FROM
     (
     SELECT DISTINCT y.millis FROM
     (
     SELECT RIGHT(RTRIM(LTRIM(x.d)), 6) AS millis FROM (
     SELECT convert(char(32), d, 139) AS d FROM DatetimeTest
     ) x
     ) y
     ) z                                                  
    

    … rendeu exatamente 300.

    O acima estabelece que o servidor é capaz de armazenar apenas 300 valores distintos para a segunda parte fracionária. Isso não prova que os valores reais mantidos são múltiplos de 1/300 de segundo, mas é uma indicação razoável.

    O que o acima implica é que qualquer armazenamento de segundos fracionários fornecido pelo cliente ao servidor é potencialmente com perdas. Portanto, fiz alguns testes adicionais para estabelecer exatamente o quão com perdas. O que encontrei é o seguinte:

    • valores de tempo com segunda precisão no cliente podem ser armazenados sem perdas no servidor (tudo bem, nunca houve dúvidas sobre isso)
    • valores de tempo com precisão de décimo de segundo no cliente podem ser armazenados sem perdas no servidor
    • valores de tempo com precisão de centésimos de segundo no cliente podem ser armazenados sem perdas no servidor
    • apenas 10% dos valores de tempo com precisão de milissegundos no cliente podem ser armazenados sem perdas no servidor (os correspondentes a centésimos de segundo completos). Para os 90% restantes dos valores pode-se observar uma diferença entre o que o cliente forneceu e o que o servidor armazenou até (e inclusive) 3ms.

    O acima é consistente com a hipótese do servidor armazenar o componente de tempo como um número inteiro de 1/300s de segundo como:

    • qualquer décimo de segundo valor pode ser expresso exatamente como uma fração na forman/300
    • qualquer centésimo de segundo valor pode ser expresso exatamente como uma fração na forman/300
    • apenas 10% dos possíveis valores de milissegundos podem ser expressos exatamente como uma fração na forma n/300.

    Por fim, fica claro que há algo errado com a convertfunção conforme a consulta:

    SELECT convert(char(32), d, 139) AS d FROM DatetimeTest
    

    … relata zeros além do terceiro ponto decimal, o que claramente não é correto e confuso. Mas não acredito que refute o que foi dito acima.

    atualização II

    Estranhamente, a porcentagem relatada pelo meu código de teste para mapeamentos de servidor não exatos para valores de milissegundos é de 90% apenas quando uso em meus testes o driver Sybase jConnect JDBC . Para o driver JTDS JDBC de código aberto, aplicam -se 70% aprimorados e maravilhosamente redondos. Basicamente, a lógica de teste é que eu crio um valor com precisão de milissegundos no lado do cliente, armazeno-o no servidor e, em seguida, leio-o novamente do cliente para ver o que recebo. Esse arranjo de teste permite que o driver do lado do cliente corrija suavemente alguns valores do servidor no caminho de volta (quando o código do lado do cliente for lido no banco de dados).

    Aparentemente, o driver JTDS pode explicar de maneira mais inteligente a maneira idiossincrática em que o servidor Sybase armazena o segundo componente fracionário e pode fazê-lo para todos os 300 valores distintos do servidor (compensando o erro de arredondamento na direção reversa - do servidor para o cliente - conforme necessário), não apenas para aqueles 100 que correspondem exatamente a algum valor de milissegundo na faixa de 0-1000.

    De qualquer forma, isso não altera os fatos no lado do servidor e só é relevante se houver controle sobre o idioma e o driver do lado do cliente que serão usados ​​para extrair Datetimevalores do servidor.

    Pensei em pular essa parte para manter as coisas simples, mas então pensei em adicioná-la para completar. Também corrobora o modelo de armazenamento de Datetimevalores do servidor, pois todos esses números (300, 90%, 70%) se encaixam na narrativa. Mas a vida é muito curta, hora de seguir em frente.

    • 4

relate perguntas

  • Restrição de chave estrangeira no campo de valor fixo

  • Por que usar TRUNCATE e DROP?

  • Existe um -w equivalente para isql quando já conectado?

  • Como posso passar parâmetros para um "Script SQL" do isql

  • Como identifico tabelas que possuem uma chave estrangeira para uma tabela específica no Sybase?

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