Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

datetime vs datetime2 in SQL Server:qual è la differenza?

Questo articolo esplora le principali differenze tra datetime e dataora2 tipi di dati in SQL Server.

Se non sei sicuro di quale utilizzare, utilizza datetime2 (vedi i suoi vantaggi sotto).

Ecco una tabella che delinea le differenze principali tra questi due tipi.

Funzione datetime datetime2
Conforme a SQL (ANSI e ISO 8601) No
Intervallo di date 01-01-1753 a 31-12-9999 0001-01-01 al 31-12-9999
Intervallo di tempo 00:00:00 alle 23:59:59.997 00:00:00 alle 23:59:59.9999999
Lunghezza del personaggio 19 posizioni minimo
23 massimo
19 posizioni minimo
27 massimo
Dimensioni di archiviazione 8 byte Da 6 a 8 byte, a seconda della precisione*

* Più 1 byte per memorizzare la precisione

Precisione Arrotondato a incrementi di .000, .003 o .007 secondi 100 nanosecondi
Precisione al secondo frazionario definita dall'utente No
Offset fuso orario Nessuno Nessuno
Consapevolezza e conservazione della differenza di fuso orario No No
Attenzione all'ora legale No No

Vantaggi di "datetime2"

Come si vede nella tabella sopra, il datetime2 il tipo ha molti vantaggi rispetto a datetime , tra cui:

  • intervallo di date più ampio
  • precisione frazionaria predefinita maggiore
  • precisione specificata dall'utente opzionale
  • maggiore precisione, anche utilizzando lo stesso numero di cifre decimali di datetime (cioè 3)
  • dimensioni di archiviazione inferiori quando si utilizza lo stesso numero di cifre decimali di datetime , ma con maggiore precisione*
  • l'opzione per utilizzare 2 byte di spazio di archiviazione in meno rispetto a datetime (anche se con precisione inferiore)*
  • si allinea con gli standard SQL (ANSI e ISO 8601)

* In alcuni casi un datetime2 value utilizza un byte in più per memorizzare la precisione, che risulterebbe nella stessa dimensione di archiviazione di datetime quando si utilizza lo stesso numero di cifre decimali. Continua a leggere per saperne di più.

Devo usare "datetime" o "datetime2"?

Microsoft consiglia datetime2 su data e ora per nuovi lavori (e per gli stessi motivi sopra elencati).

Pertanto, dovresti utilizzare datetime2 , a meno che tu non abbia un motivo specifico per non farlo (come lavorare con un sistema legacy).

Esempio 1 – Confronto di base

Ecco un rapido esempio per dimostrare la differenza fondamentale tra datetime e dataora2 .

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';

Risultato:

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

Qui, ho impostato una data e ora variabile allo stesso valore di datetime2 variabile. Questo fa sì che il valore venga convertito in datetime e possiamo quindi utilizzare un SELECT dichiarazione per vedere il risultato.

In questo caso, il datetime2 variabile usa una scala di 7, che significa 7 cifre decimali. La data e ora value, invece, utilizza solo 3 cifre decimali e l'ultima cifra frazionaria viene arrotondata per eccesso (poiché questo tipo di dati arrotonda i secondi frazionari a incrementi di .000, .003 o .007 secondi).

Esempio 2:utilizzo di 3 cifre decimali

Se riduco datetime2 scala a 3 (per abbinare datatime ), ecco cosa succede.

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';

Risultato:

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

Quindi datetime2 anche in questo caso il valore viene arrotondato per eccesso. Tuttavia, viene arrotondato solo a 556 – non passa a 557 come il data/ora il valore lo fa.

Naturalmente, l'unico motivo è datetime2 il valore è arrotondato per eccesso perché la cifra successiva è 5 o superiore. Se riduciamo la cifra seguente, non viene eseguito alcun arrotondamento:

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';

Risultato:

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

Tuttavia, il data/ora il valore continua ad essere arrotondato per eccesso.

Esempio 3 – Impostazione di valori da stringhe letterali

Negli esempi precedenti, il datatime il valore è stato assegnato impostandolo sullo stesso valore di datetime2 valore. Quando lo facciamo, SQL Server esegue una conversione implicita in modo che i dati "si adattino" al nuovo tipo di dati.

Tuttavia, se proviamo ad assegnare la stessa stringa letterale a datetime variabile assegnata a datetime2 , otteniamo un errore:

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';

Risultato:

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

Questo perché datetime accetta solo stringhe letterali che hanno 3 o meno secondi frazionari.

Quindi, per ovviare a questo problema, dobbiamo ridurre la parte frazionaria a sole 3 (o meno) cifre decimali.

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';

Risultato:

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

La dataora2 type non ha questa limitazione, anche quando si utilizza una scala di 3.

Esempio 4 – Dimensioni di archiviazione

La data e ora il tipo di dati ha una dimensione di archiviazione fissa di 8 byte.

La dataora2 d'altra parte, può essere 6, 7 o 8 byte, a seconda della sua precisione.

Quando utilizzi 3 cifre decimali, datetime2 utilizza solo 7 byte, il che significa che utilizza meno spazio di archiviazione di datetime (con maggiore precisione).

Tuttavia, Microsoft afferma che datetime2 type utilizza anche 1 byte in più per memorizzare la sua precisione. Quindi, in questo caso, userebbe 8 byte. E possiamo quindi rivedere l'affermazione precedente dicendo che utilizza 7, 8 o 9 byte.

Tuttavia, questo probabilmente dipende dal fatto che lo stiamo memorizzando in una tabella o in una variabile e se lo stiamo convertendo o meno in una costante binaria.

Ecco cosa succede se utilizziamo DATALENGTH() funzione per restituire il numero di byte utilizzati per ciascuno dei nostri valori:

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';

Risultato

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

Ma se li convertiamo in varbinary , otteniamo quanto segue:

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';

Risultato

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

Quindi dataora2 utilizza un byte in più quando viene convertito in varbinary , portandolo così alla stessa dimensione di archiviazione di datetime .

Tuttavia, l'esempio seguente mostra che quando i dati sono archiviati in una colonna del database, otteniamo una lunghezza di 7 byte per datetime2 e 8 byte per datetime .

Durante la memorizzazione di datetime2 valori in un database, la definizione di colonna include la precisione. In questo caso i valori in ogni riga non hanno bisogno del byte extra per memorizzare la precisione e possiamo dire che datetime2 utilizza meno spazio di archiviazione di datetime quando si utilizza lo stesso numero di secondi frazionari.

Esempio 5 – Dimensioni di archiviazione per i dati archiviati

In questo esempio creo un database e utilizzo COL_LENGTH per restituire la lunghezza di ciascuna colonna, in byte. Quindi inserisco un datetime2 e data e ora valore in esso e utilizzare DBCC PAGE() per trovare la lunghezza dei dati effettivi nel file di paging. Questo ci mostra lo spazio di archiviazione utilizzato da ciascun tipo di dati quando viene archiviato in un database.

Crea un database:

CREATE DATABASE CompareTypes;

Crea una tabella:

USE CompareTypes;

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

In questo caso creo due colonne:una è un datetime colonna e l'altra è una datetime2 colonna.

Controlla la lunghezza della colonna

Controlla la lunghezza (in byte) di ogni colonna:

SELECT 
  COL_LENGTH ( 'dbo.Datetime2vsDatetime' , 'TheDateTime2' ) AS 'datetime2',
  COL_LENGTH ( 'dbo.Datetime2vsDatetime' , 'TheDateTime' ) AS 'datetime';  

Risultato:

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

Quindi vediamo che il datetime2 la colonna ha una lunghezza di 7 byte, rispetto a datetime 's lunghezza di 8 byte.

Inserisci dati

Ora esaminiamo le dimensioni di archiviazione dei valori di data e ora effettivi quando sono archiviati in SQL Server. Possiamo usare DBCC PAGE() per controllare la pagina effettiva nel file di dati.

Ma prima dobbiamo inserire i dati nelle nostre colonne.

Inserisci dati:

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

Seleziona i dati (solo per verificarli):

SELECT * FROM Datetime2vsDatetime;

Risultato:

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

Utilizzo di DBCC PAGE()

Qui è dove usiamo DBCC PAGE() per controllare la pagina effettiva nel file di dati.

Per prima cosa, utilizzeremo DBCC IND() per trovare il PagePID:

DBCC IND('CompareTypes', 'dbo.Datetime2vsDatetime', 0);

Risultato (usando l'output verticale):

-[ 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

Questo restituisce due record. Siamo interessati al PageType di 1 (il 2° record). Vogliamo il PagePID da quel record. In questo caso il PagePID è 320 .

Ora possiamo prendere quel PagePID e usarlo nel modo seguente:

DBCC TRACEON(3604, -1);
DBCC PAGE(CompareTypes, 1, 320, 3);

Questo produce molti dati, ma siamo principalmente interessati alla parte seguente:

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                                    

Questo mostra che data e ora utilizza una lunghezza di 8 byte e datetime2(3) utilizza 7 byte quando è archiviato in un database.

Quindi questo rafforza la tesi per l'utilizzo di datetime2 su data e ora durante la progettazione di nuovi database, soprattutto se le dimensioni dello spazio di archiviazione sono un problema.