Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

datetime vs datetime2 no SQL Server:qual é a diferença?


Este artigo explora as principais diferenças entre o datetime e datetime2 tipos de dados no SQL Server.

Se você não tiver certeza de qual usar, use datetime2 (veja suas vantagens abaixo).



Aqui está uma tabela que descreve as principais diferenças entre esses dois tipos.
Recurso datahora datahora2
Compatível com SQL (ANSI e ISO 8601) Não Sim
Período 1753-01-01 a 9999-12-31 0001-01-01 a 9999-12-31
Intervalo de tempo 00:00:00 até 23:59:59.997 00:00:00 até 23:59:59.9999999
Comprimento do caractere mínimo de 19 posições
máximo de 23
19 posições no mínimo
27 no máximo
Tamanho do armazenamento 8 bytes 6 a 8 bytes, dependendo da precisão*

* Mais 1 byte para armazenar a precisão
Precisão Arredondado para incrementos de 0,000, 0,003 ou 0,007 segundos 100 nanossegundos
Precisão de segundo fracionário definida pelo usuário Não Sim
Deslocamento de fuso horário Nenhum Nenhum
Reconhecimento e preservação de deslocamento de fuso horário Não Não
Conhece o horário de verão Não Não

Vantagens de 'datetime2'


Conforme visto na tabela acima, o datetime2 type tem muitas vantagens sobre datetime , Incluindo:
  • maior intervalo de datas
  • maior precisão fracionária padrão
  • precisão opcional especificada pelo usuário
  • maior precisão, mesmo ao usar o mesmo número de casas decimais que datetime (ou seja, 3)
  • menor tamanho de armazenamento ao usar o mesmo número de casas decimais que datetime , mas com maior precisão*
  • a opção de usar 2 bytes a menos de armazenamento do que datetime (embora com menor precisão)*
  • se alinha com os padrões SQL (ANSI e ISO 8601)

* Em alguns casos, um datetime2 value usa um byte extra para armazenar a precisão, o que resultaria no mesmo tamanho de armazenamento que datetime ao usar o mesmo número de casas decimais. Continue lendo para saber mais sobre isso.

Devo usar 'datetime' ou 'datetime2'?


A Microsoft recomenda datetime2 em datahora para novos trabalhos (e pelos mesmos motivos listados acima).

Portanto, você deve usar datetime2 , a menos que você tenha um motivo específico para não fazê-lo (como trabalhar com um sistema legado).

Exemplo 1 – Comparação básica


Aqui está um exemplo rápido para demonstrar a diferença básica entre datetime e datetime2 .
DECLARE 
  @thedatetime2 datetime2(7), 
  @thedatetime datetime;
SET @thedatetime2 = '2025-05-21 10:15:30.5555555';
SET @thedatetime = @thedatetime2;
SELECT 
  @thedatetime2 AS 'datetime2',
  @thedatetime AS 'datetime';

Resultado:
+-----------------------------+-------------------------+
| datetime2                   | datetime                |
|-----------------------------+-------------------------|
| 2025-05-21 10:15:30.5555555 | 2025-05-21 10:15:30.557 |
+-----------------------------+-------------------------+

Aqui, defino um datetime variável para o mesmo valor que datetime2 variável. Isso faz com que o valor seja convertido em datetime e podemos então usar um SELECT declaração para ver o resultado.

Nesse caso, o datetime2 variável usa uma escala de 7, o que significa 7 casas decimais. O datahora value, por outro lado, usa apenas 3 casas decimais e seu último dígito fracionário é arredondado para cima (porque esse tipo de dados arredonda os segundos fracionários para incrementos de 0,000, 0,003 ou 0,007 segundos).

Exemplo 2 – Usando 3 casas decimais


Se eu reduzir o datetime2 escala para 3 (para corresponder a data ), eis o que acontece.
DECLARE 
  @thedatetime2 datetime2(3), 
  @thedatetime datetime;
SET @thedatetime2 = '2025-05-21 10:15:30.5555555';
SET @thedatetime = @thedatetime2;
SELECT 
  @thedatetime2 AS 'datetime2',
  @thedatetime AS 'datetime';

Resultado:
+-------------------------+-------------------------+
| datetime2               | datetime                |
|-------------------------+-------------------------|
| 2025-05-21 10:15:30.556 | 2025-05-21 10:15:30.557 |
+-------------------------+-------------------------+

Portanto, o datetime2 valor também é arredondado neste caso. No entanto, só é arredondado para 556 – não salta para 557 como o datahora valor faz.

Claro, a única razão pela qual o datetime2 valor é arredondado é porque o dígito seguinte é 5 ou superior. Se reduzirmos o dígito a seguir, nenhum arredondamento será realizado:
DECLARE 
  @thedatetime2 datetime2(3), 
  @thedatetime datetime;
SET @thedatetime2 = '2025-05-21 10:15:30.5554444';
SET @thedatetime = @thedatetime2;
SELECT 
  @thedatetime2 AS 'datetime2',
  @thedatetime AS 'datetime';

Resultado:
+-------------------------+-------------------------+
| datetime2               | datetime                |
|-------------------------+-------------------------|
| 2025-05-21 10:15:30.555 | 2025-05-21 10:15:30.557 |
+-------------------------+-------------------------+

No entanto, o datetime o valor continua a ser arredondado.

Exemplo 3 – Definindo valores de literais de string


Nos exemplos anteriores, o datime o valor foi atribuído definindo-o com o mesmo valor que datetime2 valor. Quando fazemos isso, o SQL Server realiza uma conversão implícita para que os dados “se ajustem” ao novo tipo de dados.

No entanto, se tentarmos atribuir o mesmo literal de string ao datetime variável que atribuímos a datetime2 , obtemos um erro:
DECLARE 
  @thedatetime2 datetime2(3), 
  @thedatetime datetime;
SET @thedatetime2 = '2025-05-21 10:15:30.5554444';
SET @thedatetime = '2025-05-21 10:15:30.5554444';
SELECT 
  @thedatetime2 AS 'datetime2',
  @thedatetime AS 'datetime';

Resultado:
Msg 241, Level 16, State 1, Line 5
Conversion failed when converting date and/or time from character string.

Isso ocorre porque datetime aceita apenas literais de string com 3 ou menos segundos fracionários.

Então, para superar esse problema, precisamos reduzir a parte fracionária para apenas 3 (ou menos) casas decimais.
DECLARE 
  @thedatetime2 datetime2(3), 
  @thedatetime datetime;
SET @thedatetime2 = '2025-05-21 10:15:30.5554444';
SET @thedatetime = '2025-05-21 10:15:30.555';
SELECT 
  @thedatetime2 AS 'datetime2',
  @thedatetime AS 'datetime';

Resultado:
+-------------------------+-------------------------+
| datetime2               | datetime                |
|-------------------------+-------------------------|
| 2025-05-21 10:15:30.555 | 2025-05-21 10:15:30.557 |
+-------------------------+-------------------------+

O datetime2 type não tem essa limitação, mesmo usando uma escala de 3.

Exemplo 4 – Tamanho de armazenamento


O datahora tipo de dados tem um tamanho de armazenamento fixo de 8 bytes.

O datetime2 por outro lado, pode ter 6, 7 ou 8 bytes, dependendo de sua precisão.

Ao usar 3 casas decimais, datetime2 usa apenas 7 bytes, o que significa que usa menos espaço de armazenamento do que datetime (com mais precisão).

No entanto, a Microsoft afirma que o datetime2 type também usa 1 byte extra para armazenar sua precisão. Então, neste caso, ele usaria 8 bytes. E podemos, portanto, revisar a declaração anterior dizendo que ela usa 7, 8 ou 9 bytes.

No entanto, isso provavelmente depende se estamos armazenando em uma tabela ou em uma variável e se estamos convertendo ou não em uma constante binária.

Aqui está o que acontece se usarmos o DATALENGTH() função para retornar o número de bytes usados ​​para cada um dos nossos valores:
DECLARE 
  @thedatetime2 datetime2(3), 
  @thedatetime datetime;
SET @thedatetime2 = '2025-05-21 10:15:30.5554444';
SET @thedatetime = @thedatetime2;
SELECT 
  DATALENGTH(@thedatetime2) AS 'datetime2',
  DATALENGTH(@thedatetime) AS 'datetime';

Resultado
+-------------+------------+
| datetime2   | datetime   |
|-------------+------------|
| 7           | 8          |
+-------------+------------+

Mas se os convertermos em varbinary , obtemos o seguinte:
DECLARE 
  @thedatetime2 datetime2(3), 
  @thedatetime datetime;
SET @thedatetime2 = '2025-05-21 10:15:30.5554444';
SET @thedatetime = @thedatetime2;
SELECT 
  DATALENGTH(CONVERT(VARBINARY(16),@thedatetime2)) AS 'datetime2',
  DATALENGTH(CONVERT(VARBINARY(16),@thedatetime)) AS 'datetime';

Resultado
+-------------+------------+
| datetime2   | datetime   |
|-------------+------------|
| 8           | 8          |
+-------------+------------+

Então datetime2 usa um byte extra quando convertido em varbinary , trazendo-o para o mesmo tamanho de armazenamento que datetime .

No entanto, o exemplo a seguir mostra que, quando os dados são armazenados em uma coluna do banco de dados, obtemos um comprimento de 7 bytes para datetime2 e 8 bytes para datetime .

Ao armazenar datetime2 valores em um banco de dados, a definição de coluna inclui a precisão. Nesse caso, os valores em cada linha não precisam do byte extra para armazenar a precisão, e podemos dizer que datetime2 usa menos espaço de armazenamento do que datetime ao usar o mesmo número de segundos fracionários.

Exemplo 5 – Tamanho de armazenamento para dados armazenados


Neste exemplo, crio um banco de dados e uso COL_LENGTH para retornar o comprimento de cada coluna, em bytes. Em seguida, insiro um datetime2 e datahora valor nele e use DBCC PAGE() para encontrar o comprimento dos dados reais no arquivo de paginação. Isso nos mostra o espaço de armazenamento que cada tipo de dados usa quando armazenado em um banco de dados.

Crie um banco de dados:
CREATE DATABASE CompareTypes;

Crie uma tabela:
USE CompareTypes;

CREATE TABLE Datetime2vsDatetime (
    TheDateTime datetime,
    TheDateTime2 datetime2(3)
    );

Neste caso eu crio duas colunas – uma é um datetime coluna e a outra é uma datetime2 coluna.

Verifique o comprimento da coluna


Verifique o comprimento (em bytes) de cada coluna:
SELECT 
  COL_LENGTH ( 'dbo.Datetime2vsDatetime' , 'TheDateTime2' ) AS 'datetime2',
  COL_LENGTH ( 'dbo.Datetime2vsDatetime' , 'TheDateTime' ) AS 'datetime';  

Resultado:
+-------------+------------+
| datetime2   | datetime   |
|-------------+------------|
| 7           | 8          |
+-------------+------------+

Assim, vemos que o datetime2 coluna tem um comprimento de 7 bytes, em comparação com datetime comprimento de 8 bytes.

Inserir dados


Agora vamos ver o tamanho do armazenamento dos valores reais de data e hora quando eles são armazenados no SQL Server. Podemos usar DBCC PAGE() para inspecionar a página real no arquivo de dados.

Mas primeiro, precisamos inserir dados em nossas colunas.

Inserir dados:
DECLARE @thedatetime2 datetime2 = '2025-05-21 10:15:30.5554444';
INSERT INTO Datetime2vsDatetime ( TheDateTime, TheDateTime2 )
SELECT @thedatetime2, @thedatetime2;

Selecione os dados (só para conferir):
SELECT * FROM Datetime2vsDatetime;

Resultado:
+-------------------------+-------------------------+
| TheDateTime             | TheDateTime2            |
|-------------------------+-------------------------|
| 2025-05-21 10:15:30.557 | 2025-05-21 10:15:30.555 |
+-------------------------+-------------------------+

Usando DBCC PAGE()


Aqui é onde usamos DBCC PAGE() para inspecionar a página real no arquivo de dados.

Primeiro, usaremos DBCC IND() para encontrar o PagePID:
DBCC IND('CompareTypes', 'dbo.Datetime2vsDatetime', 0);

Resultado (usando saída vertical):
-[ RECORD 1 ]-------------------------
PageFID         | 1
PagePID         | 307
IAMFID          | NULL
IAMPID          | NULL
ObjectID        | 885578193
IndexID         | 0
PartitionNumber | 1
PartitionID     | 72057594042974208
iam_chain_type  | In-row data
PageType        | 10
IndexLevel      | NULL
NextPageFID     | 0
NextPagePID     | 0
PrevPageFID     | 0
PrevPagePID     | 0
-[ RECORD 2 ]-------------------------
PageFID         | 1
PagePID         | 320
IAMFID          | 1
IAMPID          | 307
ObjectID        | 885578193
IndexID         | 0
PartitionNumber | 1
PartitionID     | 72057594042974208
iam_chain_type  | In-row data
PageType        | 1
IndexLevel      | 0
NextPageFID     | 0
NextPagePID     | 0
PrevPageFID     | 0
PrevPagePID     | 0

Isso retorna dois registros. Estamos interessados ​​no PageType de 1 (o segundo registro). Queremos o PagePID desse registro. Neste caso, o PagePID é 320 .

Agora podemos pegar esse PagePID e usá-lo da seguinte forma:
DBCC TRACEON(3604, -1);
DBCC PAGE(CompareTypes, 1, 320, 3);

Isso produz muitos dados, mas estamos interessados ​​principalmente na seguinte parte:
Slot 0 Column 1 Offset 0x4 Length 8 Length (physical) 8

TheDateTime = 2025-05-21 10:15:30.557                                    

Slot 0 Column 2 Offset 0xc Length 7 Length (physical) 7

TheDateTime2 = 2025-05-21 10:15:30.555                                    

Isso mostra que datetime usa um comprimento de 8 bytes e datetime2(3) usa 7 bytes quando armazenado em um banco de dados.

Portanto, isso reforça o uso de datetime2 em datahora ao projetar novos bancos de dados, especialmente se o tamanho do armazenamento for uma preocupação.