Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

datetime vs datetime2 dans SQL Server :quelle est la différence ?

Cet article explore les principales différences entre le datetime et datetime2 types de données dans SQL Server.

Si vous ne savez pas lequel utiliser, utilisez datetime2 (voir ses avantages ci-dessous).

Voici un tableau qui décrit les principales différences entre ces deux types.

Fonctionnalité dateheure datetime2
Conformité SQL (ANSI et ISO 8601) Non Oui
Plage de dates 1753-01-01 à 9999-12-31 0001-01-01 à 9999-12-31
Plage de temps 00:00:00 à 23:59:59.997 00:00:00 à 23:59:59.9999999
Longueur des caractères 19 postes minimum
23 maximum
19 postes minimum
27 maximum
Taille de stockage 8 octets 6 à 8 octets, selon la précision*

* Plus 1 octet pour stocker la précision

Précision Arrondi à des incréments de .000, .003 ou .007 secondes 100 nanosecondes
Précision fractionnaire de seconde définie par l'utilisateur Non Oui
Décalage du fuseau horaire Aucun Aucun
Conscience et préservation du décalage horaire Non Non
Respect de l'heure d'été Non Non

Avantages de "datetime2"

Comme indiqué dans le tableau ci-dessus, le datetime2 type présente de nombreux avantages par rapport à datetime , y compris :

  • plage de dates plus large
  • plus grande précision fractionnaire par défaut
  • précision facultative spécifiée par l'utilisateur
  • précision supérieure, même en utilisant le même nombre de décimales que datetime (c'est-à-dire 3)
  • moins de taille de stockage lors de l'utilisation du même nombre de décimales que datetime , mais avec une plus grande précision*
  • l'option d'utiliser 2 octets de stockage en moins que datetime (bien qu'avec une précision moindre)*
  • conforme aux normes SQL (ANSI et ISO 8601)

* Dans certains cas, un datetime2 value utilise un octet supplémentaire pour stocker la précision, ce qui donnerait la même taille de stockage que datetime en utilisant le même nombre de décimales. Lisez la suite pour en savoir plus à ce sujet.

Dois-je utiliser "datetime" ou "datetime2" ?

Microsoft recommande datetime2 sur datetime pour un nouveau travail (et pour les mêmes raisons énumérées ci-dessus).

Par conséquent, vous devez utiliser datetime2 , sauf si vous avez une raison spécifique de ne pas le faire (par exemple, si vous travaillez avec un ancien système).

Exemple 1 - Comparaison de base

Voici un exemple rapide pour démontrer la différence fondamentale entre datetime et 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';

Résultat :

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

Ici, j'ai défini un datetime variable à la même valeur que datetime2 variable. Cela entraîne la conversion de la valeur en datetime et nous pouvons alors utiliser un SELECT déclaration pour voir le résultat.

Dans ce cas, la datetime2 variable utilise une échelle de 7, ce qui signifie 7 décimales. La dateheure d'autre part, utilise seulement 3 décimales et son dernier chiffre fractionnaire est arrondi (car ce type de données arrondit les fractions de seconde à des incréments de 0,000, 003 ou 007 secondes).

Exemple 2 - Utilisation de 3 décimales

Si je réduis le datetime2 échelle à 3 (pour correspondre à dateime ), voici ce qui se passe.

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

Résultat :

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

Ainsi, le datetime2 la valeur est également arrondie dans ce cas. Cependant, il n'est arrondi qu'à 556 – il ne saute pas à 557 comme le datetime la valeur le fait.

Bien sûr, la seule raison pour laquelle le datetime2 la valeur est arrondie parce que le chiffre suivant est supérieur ou égal à 5. Si nous réduisons le chiffre suivant, aucun arrondi n'est effectué :

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

Résultat :

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

Cependant, la datetime la valeur continue d'être arrondie.

Exemple 3 - Définition de valeurs à partir de littéraux de chaîne

Dans les exemples précédents, la dateime la valeur a été attribuée en la définissant sur la même valeur que datetime2 valeur. Lorsque nous faisons cela, SQL Server effectue une conversion implicite afin que les données « correspondent » au nouveau type de données.

Cependant, si nous essayons d'attribuer le même littéral de chaîne à la datetime variable que nous avons assignée à datetime2 , nous obtenons une erreur :

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

Résultat :

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

C'est parce que datetime accepte uniquement les littéraux de chaîne qui ont 3 fractions de seconde ou moins.

Donc, pour surmonter ce problème, nous devons réduire la partie fractionnaire à seulement 3 décimales (ou moins).

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

Résultat :

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

Le datetime2 le type n'a pas cette limitation, même en utilisant une échelle de 3.

Exemple 4 - Taille de stockage

La dateheure Le type de données a une taille de stockage fixe de 8 octets.

Le datetime2 d'autre part, peut être de 6, 7 ou 8 octets, selon sa précision.

Lorsque vous utilisez 3 décimales, datetime2 utilise seulement 7 octets, ce qui signifie qu'il utilise moins d'espace de stockage que datetime (avec plus de précision).

Cependant, Microsoft indique que le datetime2 type utilise également 1 octet supplémentaire pour stocker sa précision. Donc, dans ce cas, il utiliserait 8 octets. Et on peut donc réviser l'instruction précédente en disant qu'elle utilise soit 7, 8 ou 9 octets.

Cependant, cela dépend probablement si nous le stockons dans une table ou dans une variable, et si nous le convertissons ou non en une constante binaire.

Voici ce qui se passe si nous utilisons le DATALENGTH() fonction pour retourner le nombre d'octets utilisés pour chacune de nos valeurs :

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

Résultat

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

Mais si nous les convertissons en varbinary , nous obtenons ceci :

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

Résultat

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

Donc datetime2 utilise un octet supplémentaire lors de la conversion en varbinary , l'amenant ainsi à la même taille de stockage que datetime .

Cependant, l'exemple suivant montre que lorsque les données sont stockées dans une colonne de base de données, nous obtenons une longueur de 7 octets pour datetime2 et 8 octets pour datetime .

Lors du stockage de datetime2 valeurs dans une base de données, la définition de colonne inclut la précision. Dans ce cas, les valeurs de chaque ligne n'ont pas besoin de l'octet supplémentaire pour stocker la précision, et nous pouvons dire que datetime2 utilise moins d'espace de stockage que datetime lors de l'utilisation du même nombre de secondes fractionnaires.

Exemple 5 - Taille de stockage pour les données stockées

Dans cet exemple, je crée une base de données et j'utilise COL_LENGTH pour renvoyer la longueur de chaque colonne, en octets. J'insère ensuite un datetime2 et dateheure valeur et utilisez DBCC PAGE() pour trouver la longueur des données réelles dans le fichier d'échange. Cela nous montre l'espace de stockage que chaque type de données utilise lorsqu'il est stocké dans une base de données.

Créer une base de données :

CREATE DATABASE CompareTypes;

Créer un tableau :

USE CompareTypes;

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

Dans ce cas, je crée deux colonnes - l'une est une datetime colonne et l'autre est une datetime2 colonne.

Vérifiez la longueur de la colonne

Vérifiez la longueur (en octets) de chaque colonne :

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

Résultat :

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

Nous voyons donc que le datetime2 la colonne a une longueur de 7 octets, par rapport à datetime est de 8 octets.

Insérer des données

Examinons maintenant la taille de stockage des valeurs de date et d'heure réelles lorsqu'elles sont stockées dans SQL Server. Nous pouvons utiliser DBCC PAGE() pour inspecter la page réelle dans le fichier de données.

Mais d'abord, nous devons insérer des données dans nos colonnes.

Insérer des données :

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

Sélectionnez les données (juste pour les vérifier) :

SELECT * FROM Datetime2vsDatetime;

Résultat :

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

Utilisation de DBCC PAGE()

Voici où nous utilisons DBCC PAGE() pour inspecter la page réelle dans le fichier de données.

Tout d'abord, nous allons utiliser DBCC IND() pour trouver le PagePID :

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

Résultat (en utilisant la sortie 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

Cela renvoie deux enregistrements. Nous sommes intéressés par le PageType de 1 (le 2e enregistrement). Nous voulons le PagePID de cet enregistrement. Dans ce cas, le PagePID est 320 .

Nous pouvons maintenant prendre ce PagePID et l'utiliser dans ce qui suit :

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

Cela produit beaucoup de données, mais nous nous intéressons principalement à la partie suivante :

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                                    

Cela montre que datetime utilise une longueur de 8 octets et datetime2(3) utilise 7 octets lorsqu'il est stocké dans une base de données.

Cela renforce donc les arguments en faveur de l'utilisation de datetime2 sur datetime lors de la conception de nouvelles bases de données, en particulier si la taille de stockage est un problème.