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

datetime vs datetime2 i SQL Server:Hvad er forskellen?

Denne artikel udforsker de vigtigste forskelle mellem dato og klokkeslæt og datetime2 datatyper i SQL Server.

Hvis du ikke er sikker på, hvilken du skal bruge, skal du bruge datetime2 (se fordelene nedenfor).

Her er en tabel, der skitserer de vigtigste forskelle mellem disse to typer.

Funktion datotid datetime2
SQL-kompatibel (ANSI &ISO 8601) Nej Ja
Datointerval 1753-01-01 til 9999-12-31 0001-01-01 til 9999-12-31
Tidsinterval 00:00:00 til 23:59:59.997 00:00:00 til 23:59:59.9999999
Tegnlængde 19 positioner minimum
23 maksimum
19 stillinger minimum
27 maksimum
Lagerstørrelse 8 bytes 6 til 8 bytes, afhængig af præcisionen*

* Plus 1 byte til at gemme præcisionen

Nøjagtighed Afrundet til trin på 0,000, 003 eller 0,007 sekunder 100 nanosekunder
Brugerdefineret brøksekundpræcision Nej Ja
Tidszoneforskydning Ingen Ingen
Opmærksomhed og bevarelse af tidszoneforskydning Nej Nej
Sommertid opmærksom på Nej Nej

Fordele ved 'datetime2'

Som det ses i ovenstående tabel, er datetime2 type har mange fordele i forhold til datetime , herunder:

  • større datointerval
  • større standard brøkpræcision
  • valgfri brugerspecificeret præcision
  • højere nøjagtighed, selv når du bruger det samme antal decimaler som datotid (dvs. 3)
  • mindre lagerstørrelse ved brug af det samme antal decimaler som datotid , dog med højere nøjagtighed*
  • muligheden for at bruge 2 bytes mindre lagerplads end datetime (omend med lavere præcision)*
  • tilpasser SQL-standarderne (ANSI &ISO 8601)

* I nogle tilfælde en datetime2 værdi bruger en ekstra byte til at gemme præcisionen, hvilket ville resultere i samme lagerstørrelse som datotid ved brug af samme antal decimaler. Læs videre for at finde ud af mere om dette.

Skal jeg bruge 'datetime' eller 'datetime2'?

Microsoft anbefaler datetime2 over datotid for nyt arbejde (og af de samme årsager anført ovenfor).

Derfor bør du bruge datetime2 , medmindre du har en specifik grund til ikke at gøre det (såsom at arbejde med et ældre system).

Eksempel 1 – Grundlæggende sammenligning

Her er et hurtigt eksempel til at demonstrere den grundlæggende forskel mellem datetime og 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';

Resultat:

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

Her indstiller jeg et datotidspunkt variabel til samme værdi som datetime2 variabel. Dette får værdien til at blive konverteret til datetime og vi kan derefter bruge en SELECT erklæring for at se resultatet.

I dette tilfælde er datetime2 variabel bruger en skala på 7, hvilket betyder 7 decimaler. datoen værdi på den anden side bruger kun 3 decimaler, og dets sidste brøkciffer rundes op (fordi denne datatype afrunder brøksekunderne til trin på 0,000, 003 eller 0,007 sekunder).

Eksempel 2 – Brug af 3 decimaler

Hvis jeg reducerer datetime2 skaler til 3 (for at matche datetime ), her er hvad der sker.

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

Resultat:

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

datetime2 værdien rundes også op i dette tilfælde. Det er dog kun rundet op til 556 – den hopper ikke til 557 som dato og klokkeslæt værdi gør.

Selvfølgelig er den eneste grund til datetime2 værdien rundes op, fordi det følgende ciffer er 5 eller højere. Hvis vi reducerer følgende ciffer, udføres ingen afrunding:

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

Resultat:

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

Men datotidspunktet værdi fortsætter med at blive rundet op.

Eksempel 3 – Indstilling af værdier fra strenge bogstaver

I de foregående eksempler er datetime værdien blev tildelt ved at indstille den til samme værdi som datetime2 værdi. Når vi gør det, udfører SQL Server en implicit konvertering for at dataene "passer" til den nye datatype.

Men hvis vi forsøger at tildele den samme streng bogstavelig til datetime variabel, som vi tildelte datetime2 , får vi en fejl:

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

Resultat:

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

Dette er fordi datetime accepterer kun strengliteraler, der har 3 eller færre brøksekunder.

Så for at løse dette problem skal vi reducere brøkdelen til kun 3 (eller færre) decimaler.

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

Resultat:

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

datetime2 type har ikke denne begrænsning, selv når du bruger en skala på 3.

Eksempel 4 – Lagerstørrelse

datoen datatypen har en fast lagerstørrelse på 8 bytes.

datetime2 på den anden side kan enten være 6, 7 eller 8 bytes, afhængigt af dens præcision.

Når du bruger 3 decimaler, datetime2 bruger kun 7 bytes, hvilket betyder, at den bruger mindre lagerplads end datetime (med mere nøjagtighed).

Microsoft oplyser dog, at datetime2 type bruger også 1 ekstra byte for at gemme sin præcision. Så i dette tilfælde ville det bruge 8 bytes. Og vi kan derfor revidere den tidligere erklæring ved at sige, at den bruger enten 7, 8 eller 9 bytes.

Dette afhænger dog sandsynligvis af, om vi gemmer det i en tabel eller i en variabel, og om vi konverterer det til en binær konstant eller ej.

Her er, hvad der sker, hvis vi bruger DATALENGTH() funktion til at returnere antallet af bytes brugt for hver af vores værdier:

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

Resultat

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

Men hvis vi konverterer dem til varbinary , får vi følgende:

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

Resultat

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

datetime2 bruger en ekstra byte, når den konverteres til varbinary , hvilket bringer den til samme lagerstørrelse som datetime .

Det følgende eksempel viser dog, at når dataene er gemt i en databasekolonne, får vi en længde på 7 bytes for datetime2 og 8 bytes for datetime .

Når du gemmer datetime2 værdier i en database, inkluderer kolonnedefinitionen præcisionen. I dette tilfælde behøver værdierne i hver række ikke den ekstra byte til at gemme præcisionen, og vi kan sige, at datetime2 bruger mindre lagerplads end datetime ved brug af det samme antal brøksekunder.

Eksempel 5 – Lagerstørrelse for lagrede data

I dette eksempel opretter jeg en database og bruger COL_LENGTH for at returnere hver kolonnes længde i bytes. Jeg indsætter derefter en datetime2 og datotid værdi ind i den og brug DBCC PAGE() for at finde længden af ​​de faktiske data i sidefilen. Dette viser os den lagerplads, hver datatype bruger, når den er gemt i en database.

Opret en database:

CREATE DATABASE CompareTypes;

Opret en tabel:

USE CompareTypes;

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

I dette tilfælde opretter jeg to kolonner – den ene er et datotidspunkt kolonne og den anden er en datetime2 kolonne.

Tjek kolonnelængden

Tjek længden (i bytes) af hver kolonne:

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

Resultat:

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

Så vi ser, at datetime2 kolonne har en længde på 7 bytes sammenlignet med datetime ’s længde på 8 bytes.

Indsæt data

Lad os nu se på lagerstørrelsen af ​​de faktiske dato- og tidsværdier, når de er gemt i SQL Server. Vi kan bruge DBCC PAGE() for at inspicere den faktiske side i datafilen.

Men først skal vi indsætte data i vores kolonner.

Indsæt data:

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

Vælg dataene (bare for at kontrollere dem):

SELECT * FROM Datetime2vsDatetime;

Resultat:

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

Brug af DBCC PAGE()

Det er her, vi bruger DBCC PAGE() for at inspicere den faktiske side i datafilen.

Først bruger vi DBCC IND() for at finde PagePID:

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

Resultat (ved hjælp af lodret output):

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

Dette returnerer to poster. Vi er interesserede i PageType of 1 (den 2. post). Vi vil have PagePID fra den post. I dette tilfælde er PagePID 320 .

Nu kan vi tage det PagePID og bruge det i følgende:

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

Dette producerer en masse data, men vi er primært interesserede i følgende del:

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                                    

Dette viser, at datetime bruger en længde på 8 bytes og datetime2(3) bruger 7 bytes, når den er gemt i en database.

Så dette forstærker argumentet for at bruge datetime2 over datotid når du designer nye databaser, især hvis lagerstørrelse er et problem.


  1. Få det aktuelle år, den aktuelle måned og den aktuelle dag i MySQL

  2. En oversigt over MariaDB Xpand (tidligere ClustrixDB)

  3. Hvordan trunkerer man en tabel med begrænsning af fremmednøgler?

  4. Upload CSV-fil til SQL-server