sql >> Database >  >> RDS >> Sqlserver

datetime vs datetime2 in SQL Server:wat is het verschil?

Dit artikel onderzoekt de belangrijkste verschillen tussen de datetime en datetime2 gegevenstypen in SQL Server.

Als je niet zeker weet welke je moet gebruiken, gebruik dan datetime2 (zie de voordelen hieronder).

Hier is een tabel met de belangrijkste verschillen tussen deze twee typen.

Functie datetime datetime2
SQL-compatibel (ANSI &ISO 8601) Nee Ja
Datumbereik 1753-01-01 tot 9999-12-31 0001-01-01 tot 9999-12-31
Tijdbereik 00:00:00 tot 23:59:59,997 00:00:00 tot 23:59:59,999999
Tekenlengte 19 posities minimaal
23 maximaal
19 posities minimaal
27 maximaal
Opslaggrootte 8 bytes 6 tot 8 bytes, afhankelijk van de precisie*

* Plus 1 byte om de precisie op te slaan

Nauwkeurigheid Afgerond op stappen van .000, .003 of .007 seconden 100 nanoseconden
Door gebruiker gedefinieerde precisie van fractionele seconden Nee Ja
Tijdzoneverschuiving Geen Geen
Bewustwording en behoud van tijdzoneverschuiving Nee Nee
Bewust zomertijd Nee Nee

Voordelen van ‘datetime2’

Zoals te zien is in de bovenstaande tabel, is de datetime2 type heeft veel voordelen ten opzichte van datetime , waaronder:

  • grotere periode
  • grotere standaard fractionele precisie
  • optionele door de gebruiker gespecificeerde precisie
  • hogere nauwkeurigheid, zelfs bij gebruik van hetzelfde aantal decimalen als datetime (d.w.z. 3)
  • minder opslagruimte bij gebruik van hetzelfde aantal decimalen als datetime , maar met een hogere nauwkeurigheid*
  • de optie om 2 bytes minder opslagruimte te gebruiken dan datetime (zij het met een lagere precisie)*
  • komt overeen met de SQL-standaarden (ANSI &ISO 8601)

* In sommige gevallen een datetime2 value gebruikt een extra byte om de precisie op te slaan, wat zou resulteren in dezelfde opslaggrootte als datetime bij gebruik van hetzelfde aantal decimalen. Lees verder om hier meer over te weten te komen.

Moet ik 'datetime' of 'datetime2' gebruiken?

Microsoft raadt datetime2 aan over datetime voor nieuw werk (en om dezelfde redenen als hierboven genoemd).

Gebruik daarom datetime2 , tenzij u een specifieke reden heeft om dit niet te doen (zoals werken met een legacy-systeem).

Voorbeeld 1 – Basisvergelijking

Hier is een snel voorbeeld om het fundamentele verschil te demonstreren tussen datetime en 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';

Resultaat:

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

Hier stel ik een datumtijd in variabele naar dezelfde waarde als de datetime2 variabel. Hierdoor wordt de waarde geconverteerd naar datetime en we kunnen dan een SELECT . gebruiken verklaring om het resultaat te zien.

In dit geval is de datetime2 variabele gebruikt een schaal van 7, wat 7 decimalen betekent. De datetime waarde daarentegen gebruikt slechts 3 decimalen en het laatste fractionele cijfer wordt naar boven afgerond (omdat dit gegevenstype de fractionele seconden rondt op stappen van .000, .003 of .007 seconden).

Voorbeeld 2 – 3 decimalen gebruiken

Als ik de datetime2 . verklein schaal tot 3 (om overeen te komen met datetime ), dit is wat er gebeurt.

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

Resultaat:

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

Dus de datetime2 waarde wordt in dit geval ook naar boven afgerond. Het wordt echter alleen naar boven afgerond op 556 – het springt niet naar 557 zoals de datetime waarde wel.

Natuurlijk, de enige reden waarom de datetime2 waarde naar boven wordt afgerond, omdat het volgende cijfer 5 of hoger is. Als we het volgende cijfer verkleinen, wordt er niet afgerond:

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

Resultaat:

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

Echter, de datetime waarde wordt nog steeds naar boven afgerond.

Voorbeeld 3 – Waarden instellen uit String Literals

In de vorige voorbeelden is de datetime waarde is toegewezen door deze op dezelfde waarde in te stellen als de datetime2 waarde. Wanneer we dat doen, voert SQL Server een impliciete conversie uit zodat de gegevens "passen" bij het nieuwe gegevenstype.

Als we echter proberen om dezelfde letterlijke tekenreeks toe te wijzen aan de datetime variabele die we hebben toegewezen aan datetime2 , krijgen we een foutmelding:

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

Resultaat:

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

Dit komt omdat datetime accepteert alleen letterlijke tekenreeksen die 3 of minder fractionele seconden hebben.

Om dit probleem op te lossen, moeten we het breukdeel verkleinen tot slechts 3 (of minder) decimalen.

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

Resultaat:

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

De datetime2 type heeft deze beperking niet, zelfs niet bij gebruik van een schaal van 3.

Voorbeeld 4 – Opslaggrootte

De datetime datatype heeft een vaste opslaggrootte van 8 bytes.

De datetime2 aan de andere kant kan het 6, 7 of 8 bytes zijn, afhankelijk van de nauwkeurigheid.

Bij gebruik van 3 decimalen, datetime2 gebruikt slechts 7 bytes, wat betekent dat het minder opslagruimte gebruikt dan datetime (met meer nauwkeurigheid).

Microsoft stelt echter dat de datetime2 type gebruikt ook 1 extra byte om zijn precisie op te slaan. Dus in dit geval zou het 8 bytes gebruiken. En we kunnen daarom de vorige verklaring herzien door te zeggen dat deze 7, 8 of 9 bytes gebruikt.

Dit hangt echter waarschijnlijk af van of we het in een tabel of in een variabele opslaan en of we het al dan niet converteren naar een binaire constante.

Dit is wat er gebeurt als we de DATALENGTH() . gebruiken functie om het aantal bytes terug te geven dat voor elk van onze waarden is gebruikt:

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

Resultaat

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

Maar als we ze converteren naar varbinary , krijgen we het volgende:

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

Resultaat

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

Dus datetime2 gebruikt een extra byte bij conversie naar varbinary , waardoor het dezelfde opslaggrootte krijgt als datetime .

Het volgende voorbeeld laat echter zien dat wanneer de gegevens worden opgeslagen in een databasekolom, we een lengte krijgen van 7 bytes voor datetime2 en 8 bytes voor datetime .

Bij het opslaan van datetime2 waarden in een database, bevat de kolomdefinitie de precisie. In dit geval hebben de waarden in elke rij geen extra byte nodig om de precisie op te slaan, en we kunnen zeggen dat datetime2 gebruikt minder opslagruimte dan datetime wanneer hetzelfde aantal fracties van seconden wordt gebruikt.

Voorbeeld 5 – Opslaggrootte voor opgeslagen gegevens

In dit voorbeeld maak ik een database en gebruik ik COL_LENGTH om de lengte van elke kolom in bytes te retourneren. Ik voeg dan een datetime2 . in en datetime waarde erin en gebruik DBCC PAGE() om de lengte van de werkelijke gegevens in het paginabestand te vinden. Dit toont ons de opslagruimte die elk gegevenstype gebruikt wanneer het wordt opgeslagen in een database.

Maak een database:

CREATE DATABASE CompareTypes;

Maak een tabel:

USE CompareTypes;

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

In dit geval maak ik twee kolommen - één is een datetime kolom en de andere is een datetime2 kolom.

Controleer de kolomlengte

Controleer de lengte (in bytes) van elke kolom:

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

Resultaat:

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

We zien dus dat de datetime2 kolom heeft een lengte van 7 bytes, vergeleken met datetime 's lengte van 8 bytes.

Gegevens invoegen

Laten we nu eens kijken naar de opslaggrootte van de werkelijke datum- en tijdwaarden wanneer ze zijn opgeslagen in SQL Server. We kunnen DBCC PAGE() . gebruiken om de eigenlijke pagina in het gegevensbestand te inspecteren.

Maar eerst moeten we gegevens in onze kolommen invoegen.

Gegevens invoegen:

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

Selecteer de gegevens (om het te controleren):

SELECT * FROM Datetime2vsDatetime;

Resultaat:

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

DBCC PAGE() gebruiken

Hier gebruiken we DBCC PAGE() om de eigenlijke pagina in het gegevensbestand te inspecteren.

Eerst gebruiken we DBCC IND() om de PagePID te vinden:

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

Resultaat (met verticale uitvoer):

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

Dit levert twee records op. We zijn geïnteresseerd in het PageType van 1 (het 2e record). We willen de PagePID van dat record. In dit geval is de PagePID 320 .

Nu kunnen we die PagePID nemen en gebruiken in het volgende:

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

Dit levert veel data op, maar we zijn vooral geïnteresseerd in het volgende deel:

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                                    

Dit laat zien dat datetime gebruikt een lengte van 8 bytes en datetime2(3) gebruikt 7 bytes wanneer opgeslagen in een database.

Dit versterkt dus de argumenten voor het gebruik van datetime2 over datetime bij het ontwerpen van nieuwe databases, vooral als de opslaggrootte een probleem is.


  1. Jenkins gebruiken met Kubernetes AWS, deel 2

  2. Wordnet sqlite Synoniemen en voorbeelden

  3. Tel alle objecten in uw database

  4. 3 manieren om een ​​getal op te maken als een percentage in PostgreSQL