web-dev-qa-db-fra.com

DateTime2 vs DateTime dans SQL Server

Laquelle: 

est le moyen recommandé par the de stocker la date et l'heure dans SQL Server 2008+?

Je suis conscient des différences de précision (et d'espace de stockage probablement), mais en les ignorant pour le moment, existe-t-il un document sur les meilleures pratiques indiquant quand utiliser quoi, ou devrions-nous simplement utiliser datetime2 uniquement?

667
Mikeon

La documentation MSDN pour datetime recommande l'utilisation de datetime2 . Voici leur recommandation:

Utilisez les variables time, date, datetime2 et datetimeoffset types de données pour le nouveau travail. Ces types sont alignés sur le SQL La norme. Ils sont plus portables . time, datetime2 et datetimeoffset fournir plus de précision secondes . datetimeoffset fournit le fuseau horaire soutien au déploiement mondial applications.

datetime2 a une plage de dates plus grande, une précision fractionnelle par défaut plus grande et une précision facultative spécifiée par l'utilisateur. En outre, en fonction de la précision spécifiée par l'utilisateur, il peut utiliser moins de stockage. 

557
Adam Porad

DATETIME2 a une plage de dates allant de "0001/01/01" à "9999/12/31" alors que le type DATETIME ne prend en charge que les années 1753 à 9999.

De plus, si vous en avez besoin, DATETIME2 peut être plus précis en termes de temps; DATETIME est limité à 3 1/3 millisecondes, alors que DATETIME2 peut être précis jusqu'à 100ns.

Les deux types mappent vers System.DateTime dans .NET - il n'y a pas de différence.

Si vous avez le choix, je vous recommanderais d'utiliser DATETIME2 dès que possible. Je ne vois aucun avantage à utiliser DATETIME (à l'exception de la compatibilité ascendante) - vous aurez moins de problèmes (avec des dates hors de portée et des problèmes comme celui-ci).

De plus, si vous n’avez besoin que de la date (sans indication de temps), utilisez DATE - c’est aussi bon que DATETIME2 et vous permet également de gagner de la place! :-) Même chose pour le temps seulement - utilisez TIME. C'est pour ça que ces types sont là!

454
marc_s

_ {datetime2} _ gagne dans la plupart des aspects sauf (compatibilité d'anciennes applications)

  1. plus grand plage de valeurs 
  2. mieux précision
  3. plus petit espace de stockage} _ (si la précision facultative spécifiée par l'utilisateur est spécifiée)

SQL Date and time data types compare - datetime,datetime2,date,TIME

veuillez noter les points suivants

  • Syntaxe
    • datetime2 [(précision fractionnelle en secondes => Regarder en dessous de la taille de stockage)]
  • Précision, échelle
    • 0 à 7 chiffres, avec une précision de 100 ns. 
    • La précision par défaut est 7 chiffres.
  • Taille de stockage
    • 6 octets pour une précision inférieure à 3; 
    • 7 octets pour la précision 3 et 4. 
    • Toute autre précision nécessite 8 octets.
  • DateTime2 (3) possède le même nombre de chiffres que DateTime mais utilise 7 octets de stockage au lieu de 8 octets ( SQLHINTS- DateTime Vs DateTime2 )
  • Plus d'informations sur datetime2 (article MSDN de Transact-SQL)

source de l'image: Kit de formation auto-rythmée des SCTM (Examen 70-432): Microsoft® SQL Server® 2008 - Implémentation et maintenance Chapitre 3: Tableaux -> Leçon 1: Création de tableaux -> page 66

175
Iman Abidi

Je suis d'accord avec @marc_s et @Adam_Poward - DateTime2 est la méthode préférée pour aller de l'avant. Il a une plage de dates plus étendue, une précision supérieure et utilise un stockage égal ou inférieur (selon la précision). 

Une chose a manqué la discussion, cependant ...
@ Marc_s déclare: Both types map to System.DateTime in .NET - no difference there. C’est correct, cependant, l’inverse n’est pas vrai ... et cela est important lorsque vous effectuez des recherches dans la plage de dates (par exemple, "retrouvez tous les enregistrements modifiés le 5/5/2010"). 

La version .NET de Datetime a une plage et une précision similaires à DateTime2. Lorsque vous mappez une variable .net Datetime à l'ancienne SQL DateTime, un arrondi implicite se produit. L'ancien SQL DateTime est précis à 3 millisecondes. Cela signifie que 11:59:59.997 est aussi proche que possible de la fin de la journée. Tout ce qui est plus haut est arrondi au lendemain.

Essaye ça :

declare @d1 datetime   = '5/5/2010 23:59:59.999'
declare @d2 datetime2  = '5/5/2010 23:59:59.999'
declare @d3 datetime   = '5/5/2010 23:59:59.997'
select @d1 as 'IAmMay6BecauseOfRounding', @d2 'May5', @d3 'StillMay5Because2msEarlier'

Éviter cet arrondi implicite est une raison importante pour passer à DateTime2. L’arrondi implicite des dates est clairement source de confusion:

102
EBarr

DateTime2 fait des ravages si vous êtes un développeur Access et essayez d'écrire Now () dans le champ en question. Vient de faire une migration Access -> SQL 2008 R2 et tous les champs de date/heure ont été placés dans DateTime2. Ajouter un enregistrement avec Now () comme valeur bombardée. C'était correct le 01/01/2012 14:53:04, mais pas le 1/10/2012 14:53:04. 

Une fois le caractère a fait la différence. J'espère que ça aide quelqu'un.

15
Rhett A Brown

Voici un exemple qui vous montrera les différences de taille de stockage (en octets) et de précision entre smalldatetime, datetime, datetime2 (0) et datetime2 (7):

DECLARE @temp TABLE (
    sdt smalldatetime,
    dt datetime,
    dt20 datetime2(0),
    dt27 datetime2(7)
)

INSERT @temp
SELECT getdate(),getdate(),getdate(),getdate()

SELECT sdt,DATALENGTH(sdt) as sdt_bytes,
    dt,DATALENGTH(dt) as dt_bytes,
    dt20,DATALENGTH(dt20) as dt20_bytes,
    dt27, DATALENGTH(dt27) as dt27_bytes FROM @temp

qui retourne

sdt                  sdt_bytes  dt                       dt_bytes  dt20                 dt20_bytes  dt27                         dt27_bytes
2015-09-11 11:26:00  4          2015-09-11 11:25:42.417  8         2015-09-11 11:25:42  6           2015-09-11 11:25:42.4170000  8

Donc, si je veux stocker des informations à la seconde près, mais pas à la milliseconde, je peux économiser 2 octets chacune si j’utilise datetime2 (0) au lieu de datetime ou datetime2 (7).

13
Baodad

Presque toutes les réponses et commentaires ont été lourds sur les avantages et légers sur les inconvénients. Voici un récapitulatif de tous les avantages et inconvénients à ce jour, ainsi que des inconvénients cruciaux (au n ° 2 ci-dessous) que je n'ai vus mentionnés qu'une ou deux fois.

  1. AVANTAGES:

1.1. Plus conforme à ISO (ISO 8601) (bien que je ne sache pas comment cela entre en pratique).

1.2. Plus grande plage (1/1/0001 au 12/31/9999 vs 1/1/1753-12/31/9999) (bien que la plage supplémentaire, toutes antérieures à l'année 1753, ne sera probablement pas utilisée sauf pour ex., dans les applications historiques, astronomiques, géologiques, etc.).

1.3. Correspond exactement à la plage de la gamme DateTime Type de .NET (bien que les deux soient converties dans les deux sens sans codage spécial si les valeurs sont dans la plage et la précision du type cible, sauf pour la Con # 2.1 ci-dessous, sinon des erreurs/arrondis se produiront).

1.4. Plus de précision (100 nanosecondes, 0,000,000,1 s. Contre 3,33 millisecondes, 0,003,33 s.) (Même si la précision supplémentaire ne sera probablement pas utilisée, sauf dans les applications d'ingénierie/scientifiques, par exemple).

1.5 Lorsqu'il est configuré pour similar (comme dans 1 millisec, pas "identique" (comme dans 3,33 millisecondes) comme Iman Abidi a affirmé), la précision est DateTime, utilise moins d'espace (7 vs 8 octets), mais bien sûr, vous je perdrais le bénéfice de précision qui est probablement l’un des deux (l’autre étant la gamme) les plus vantés, bien que probablement des bénéfices inutiles).

  1. LES INCONVÉNIENTS: 

2.1. Lorsque vous transmettez un paramètre à un .NET SqlCommand, vous devez spécifier System.Data.SqlDbType.DateTime2 si vous transmettez peut-être une valeur en dehors de la plage et/ou de la précision de SQL Server DateTime, car sa valeur par défaut est System.Data.SqlDbType.DateTime.

2.2. Ne peut pas être implicitement/facilement converti en une valeur numérique à virgule flottante (nombre de jours depuis la date et l'heure min) pour effectuer les opérations suivantes dans/avec des expressions SQL Server à l'aide d'opérateurs et de valeurs numériques:

2.2.1. additionnez ou soustrayez le nombre de jours ou de jours partiels. Remarque: L'utilisation de DateAdd Function comme solution de contournement n'est pas évidente lorsque vous devez prendre en compte plusieurs, voire toutes les parties de la date et l'heure.

2.2.2. prenez la différence entre deux heures de date aux fins du calcul de «l'âge». Remarque: vous ne pouvez pas simplement utiliser la fonction DateDiff de SQL Server à la place, car elle ne calcule pas age car la plupart des gens s’y attendaient, si les deux dates se trouvaient à franchir une limite calendrier/horloge date-heure des unités spécifiées si fraction infime de cette unité, la différence sera égale à 1 contre 0. Par exemple, la DateDiff dans Day de deux heures de date séparées de seulement 1 milliseconde rendra 1 vs 0 (jours) si ces dates les heures sont différentes jours calendaires («1999-12-31 23: 59: 59.9999999» et «2000-01-01 00: 00: 00.0000000»). La même différence de 1 milliseconde date-heure, si elle est déplacée de manière à ne pas traverser un jour calendaire, renverra un «DateDiff» dans Day ’s de 0 (jours).

2.2.3. Prenez la Avg de date-heures (dans une requête d'agrégat) en convertissant simplement d'abord en «Float», puis de nouveau en DateTime.

REMARQUE: pour convertir DateTime2 en numérique, vous devez utiliser la formule suivante qui suppose que vos valeurs ne sont pas inférieures à 1970 (ce qui signifie que vous perdez toute la plage supplémentaire plus 217 ans de plus. Remarque: vous Il se peut que vous ne puissiez pas simplement ajuster la formule pour permettre une plage supplémentaire, car vous pourriez rencontrer des problèmes de débordement numérique.

25567 + (DATEDIFF(SECOND, {d '1970-01-01'}, @Time) + DATEPART(nanosecond, @Time) / 1.0E + 9) / 86400.0 - Source: “ https://siderite.blogspot.com/2015/08/how-to-translate-t-sql-datetime2-to.html

Bien sûr, vous pourriez aussi Cast à DateTime premier (et si nécessaire revenir à DateTime2), mais vous perdriez la précision et la portée (toutes antérieures à l’année 1753) des avantages de DateTime2 par rapport à DateTime qui sont les deux plus grands avantages dans le même temps, les 2 moins probables nécessaires soulèvent la question de savoir pourquoi l’utiliser lorsque vous perdez les conversions implicites/faciles en nombres à virgule flottante (nombre de jours) pour addition/soustraction/"âge" (vs DateDiff)/Avg calcs bénéfice qui est un grand dans mon expérience.

Au fait, la Avg des date-heures est (ou au moins devrait être) un cas d'utilisation important. a) Outre l'utilisation pour obtenir la durée moyenne lorsque la date/heure (étant donné qu'une date/heure de base commune) est utilisée pour représenter la durée (une pratique courante), b), il est également utile d'obtenir une statistique de type tableau de bord indiquant la date moyenne. heure est dans la colonne date-heure d'une plage/groupe de lignes. c) Une requête ad hoc standard (ou au moins devrait être standard) pour surveiller/dépanner les valeurs dans une colonne qui peut ne plus être valide/et qui doit éventuellement être obsolète doit être répertoriée pour chaque valorisez le nombre d'occurrences et (si disponible) les tampons date-heure Min, Avg et Max associés à cette valeur.

12
Tom

alors que precision est augmenté avec datetime2 , certains clients ne prennent pas en charge date, heure ou datetime2 et vous obligent à convertir en un littéral de chaîne. Plus précisément, Microsoft mentionne les problèmes ODBC, OLE DB, JDBC et SqlClient "de niveau inférieur" avec ces types de données et dispose d'un chart montrant comment chacun peut mapper le type. 

Si la valeur compatability est supérieure à la précision, utilisez datetime

8
FistOfFury

L'interprétation des chaînes de date dans datetime et datetime2 peut également être différente lors de l'utilisation de paramètres DATEFORMAT non américains. Par exemple.

set dateformat dmy
declare @d datetime, @d2 datetime2
select @d = '2013-06-05', @d2 = '2013-06-05'
select @d, @d2

Ceci retourne 2013-05-06 (c'est-à-dire le 6 mai) pour datetime et 2013-06-05 (c'est-à-dire le 5 juin) pour datetime2. Cependant, avec dateformat défini sur mdy, @d et @d2 renvoient 2013-06-05.

Le comportement datetime semble contredire le MSDN documentation of SET DATEFORMAT qui indique: Certains formats de chaînes de caractères, par exemple ISO 8601, sont interprétés indépendamment du paramètre DATEFORMAT. Évidemment pas vrai!

Jusque-là, j'avais toujours pensé que les dates de yyyy-mm-dd seraient gérées correctement, quels que soient les paramètres de langue/paramètres régionaux.

7
Richard Fawcett

Vieille question ... Mais je veux ajouter quelque chose qui n'a pas déjà été indiqué par quiconque ici ... (Remarque: ceci est ma propre observation, alors ne demandez aucune référence)

Datetime2 est plus rapide lorsqu'il est utilisé dans les critères de filtre.

TLDR:

Dans SQL 2016, j'avais une table contenant des centaines de milliers de lignes et une colonne datetime ENTRY_TIME car il était nécessaire pour stocker l'heure exacte en secondes. Lors de l'exécution d'une requête complexe comportant de nombreuses jointures et une sous requête, lorsque j'ai utilisé la clause where en tant que:

WHERE ENTRY_TIME >= '2017-01-01 00:00:00' AND ENTRY_TIME < '2018-01-01 00:00:00'

La requête était correcte initialement lorsqu'il y avait des centaines de lignes, mais lorsque le nombre de lignes augmentait, la requête commençait à donner l'erreur suivante:

Execution Timeout Expired. The timeout period elapsed prior
to completion of the operation or the server is not responding.

J'ai supprimé la clause where et, de manière inattendue, la requête a été exécutée en 1 seconde, bien que TOUTES les lignes de toutes les dates aient été extraites. J'exécute la requête interne avec la clause where, et cela a pris 85 secondes, et sans la clause where, cela a pris 0,01 seconde.

Je suis tombé sur de nombreux sujets ici pour ce problème en tant que performances de filtrage datetime

J'ai optimisé un peu la requête. Mais la vitesse réelle que j'ai obtenue était de changer la colonne datetime en datetime2.

Maintenant, la même requête qui a expiré précédemment prend moins d'une seconde.

à votre santé

5
Khan

Selon cet article , si vous voulez avoir la même précision de DateTime en utilisant DateTime2, vous devez simplement utiliser DateTime2 (3). Cela devrait vous donner la même précision, prendre un octet en moins et fournir une plage étendue. 

4
jKlaus

Je viens de trébucher sur un autre avantage pour DATETIME2: il évite un bogue dans le module Python adodbapi, qui explose si une valeur de bibliothèque standard datetime est transmise, laquelle a une valeur microseconde non nulle pour une colonne DATETIME, mais fonctionne correctement si la colonne est définie comme telle. DATETIME2.

3
Bob Kline
Select ValidUntil + 1
from Documents

Le code SQL ci-dessus ne fonctionnera pas avec un champ DateTime2 . Il retourne et l'erreur "Clash de type d'opérande: date/heure2 est incompatible avec int"

L'ajout de 1 pour obtenir le lendemain est une chose que les développeurs font avec les dates depuis des années. Maintenant, Microsoft a un nouveau champ datetime2 super qui ne peut pas gérer cette fonctionnalité simple.

"Utilisons ce nouveau type qui est pire que l'ancien", je ne pense pas!

0
Paul McCarthy

Je pense que DATETIME2 est le meilleur moyen de stocker la date, car il est plus efficace que Le DATETIME. Dans SQL Server 2008, vous pouvez utiliser DATETIME2, il stocke une date et une heure, prend 6-8 octets à stocker et a une précision de 100 nanosecondes. Ainsi, quiconque a besoin d'une plus grande précision temporelle voudra DATETIME2.

0
James