sql >> Databasteknik >  >> RDS >> Sqlserver

datetime vs datetime2 i SQL Server:Vad är skillnaden?

Den här artikeln undersöker de viktigaste skillnaderna mellan datetime och datetime2 datatyper i SQL Server.

Om du inte är säker på vilken du ska använda, använd datetime2 (se dess fördelar nedan).

Här är en tabell som beskriver de viktigaste skillnaderna mellan dessa två typer.

Funktion datumtid datetime2
SQL-kompatibel (ANSI &ISO 8601) Nej Ja
Datumintervall 1753-01-01 till 9999-12-31 0001-01-01 till 9999-12-31
Tidsintervall 00:00:00 till 23:59:59.997 00:00:00 till 23:59:59.9999999
Teckenlängd 19 positioner minst
23 max
19 positioner minst
27 max
Lagringsstorlek 8 byte 6 till 8 byte, beroende på precisionen*

* Plus 1 byte för att lagra precisionen

Noggrannhet Avrundat till steg om 0,000, 0,003 eller 0,007 sekunder 100 nanosekunder
Användardefinierad precision på bråkdelssekunder Nej Ja
Tidszonsförskjutning Inga Inga
Medveten om och bevarande av tidszonförskjutning Nej Nej
Medveten om sommartid Nej Nej

Fördelar med "datetime2"

Som framgår av tabellen ovan är datetime2 typ har många fördelar jämfört med datetime , inklusive:

  • större datumintervall
  • större standard bråkprecision
  • valfri användarspecificerad precision
  • högre noggrannhet, även när du använder samma antal decimaler som datetime (dvs. 3)
  • mindre lagringsstorlek när du använder samma antal decimaler som datetime , men med högre noggrannhet*
  • alternativet att använda 2 byte mindre lagringsutrymme än datetime (om än med lägre precision)*
  • överensstämmer med SQL-standarderna (ANSI &ISO 8601)

* I vissa fall en datetime2 värde använder en extra byte för att lagra precisionen, vilket skulle resultera i samma lagringsstorlek som datetime när du använder samma antal decimaler. Läs vidare för att ta reda på mer om detta.

Ska jag använda 'datetime' eller 'datetime2'?

Microsoft rekommenderar datetime2 över datumtid för nytt arbete (och av samma skäl som anges ovan).

Därför bör du använda datetime2 , såvida du inte har en specifik anledning att inte göra det (som att arbeta med ett äldre system).

Exempel 1 – Grundläggande jämförelse

Här är ett snabbt exempel för att visa den grundläggande skillnaden mellan datetime och 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 |
+-----------------------------+-------------------------+

Här ställer jag in en datumtid variabel till samma värde som datetime2 variabel. Detta gör att värdet konverteras till datetime och vi kan sedan använda en SELECT uttalande för att se resultatet.

I det här fallet, datetime2 variabeln använder en skala på 7, vilket betyder 7 decimaler. datetime värde å andra sidan använder bara 3 decimaler, och dess sista bråktalssiffra avrundas uppåt (eftersom denna datatyp avrundar bråksekunderna till steg om 0,000, 0,003 eller 0,007 sekunder).

Exempel 2 – Använda 3 decimaler

Om jag minskar datetime2 skala till 3 (för att matcha datetime ), här är vad som händer.

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ärdet avrundas också i detta fall. Det är dock bara avrundat till 556 – den hoppar inte till 557 som datetime värde gör.

Naturligtvis den enda anledningen till datetime2 värdet avrundas uppåt beror på att följande siffra är 5 eller högre. Om vi ​​minskar följande siffra utförs ingen avrundning:

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 datumtid värdet fortsätter att avrundas uppåt.

Exempel 3 – Ställa in värden från strängbokstaver

I de tidigare exemplen, datetime värde tilldelades genom att sätta det till samma värde som datetime2 värde. När vi gör det utför SQL Server en implicit konvertering för att data ska "passa" till den nya datatypen.

Men om vi försöker tilldela samma sträng bokstavligt till datetime variabel som vi tilldelade datetime2 , får vi ett felmeddelande:

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.

Detta beror på att datetime accepterar endast strängliteraler som har 3 eller färre bråksekunder.

Så för att lösa det här problemet måste vi minska bråkdelen till bara 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 typ har inte denna begränsning, även när du använder en skala på 3.

Exempel 4 – Förvaringsstorlek

datetime datatypen har en fast lagringsstorlek på 8 byte.

datetime2 å andra sidan kan den vara antingen 6, 7 eller 8 byte, beroende på dess precision.

När du använder 3 decimaler, datetime2 använder bara 7 byte, vilket betyder att den använder mindre lagringsutrymme än datetime (med större noggrannhet).

Microsoft uppger dock att datetime2 typ använder också 1 extra byte för att lagra dess precision. Så i det här fallet skulle den använda 8 byte. Och vi kan därför revidera det tidigare uttalandet genom att säga att det använder antingen 7, 8 eller 9 byte.

Men detta beror förmodligen på om vi lagrar det i en tabell eller i en variabel, och om vi konverterar det till en binär konstant eller inte.

Här är vad som händer om vi använder DATALENGTH() funktion för att returnera antalet byte som används för vart och ett av våra värden:

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 om vi konverterar dem till varbinary , får vi följande:

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 använder en extra byte när den konverteras till varbinary , vilket ger den samma lagringsstorlek som datetime .

Följande exempel visar dock att när data lagras i en databaskolumn får vi en längd på 7 byte för datetime2 och 8 byte för datetime .

När du lagrar datetime2 värden i en databas, inkluderar kolumndefinitionen precisionen. I det här fallet behöver värdena i varje rad inte den extra byten för att lagra precisionen, och vi kan säga att datetime2 använder mindre lagringsutrymme än datetime när du använder samma antal bråksekunder.

Exempel 5 – Lagringsstorlek för lagrad data

I det här exemplet skapar jag en databas och använder COL_LENGTH för att returnera varje kolumns längd, i byte. Jag infogar sedan en datetime2 och datumtid värde i den och använd DBCC PAGE() för att hitta längden på den faktiska datan i sidfilen. Detta visar oss vilket lagringsutrymme varje datatyp använder när de lagras i en databas.

Skapa en databas:

CREATE DATABASE CompareTypes;

Skapa en tabell:

USE CompareTypes;

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

I det här fallet skapar jag två kolumner – en är en datumtid kolumn och den andra är en datetime2 kolumn.

Kontrollera kolumnlängden

Kontrollera längden (i byte) för varje kolumn:

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

Resultat:

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

Så vi ser att datetime2 kolumnen har en längd på 7 byte, jämfört med datetime s längd på 8 byte.

Infoga data

Låt oss nu titta på lagringsstorleken för de faktiska datum- och tidsvärdena när de lagras i SQL Server. Vi kan använda DBCC PAGE() för att inspektera den faktiska sidan i datafilen.

Men först måste vi infoga data i våra kolumner.

Infoga data:

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

Välj data (bara för att kontrollera det):

SELECT * FROM Datetime2vsDatetime;

Resultat:

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

Med DBCC PAGE()

Det är här vi använder DBCC PAGE() för att inspektera den faktiska sidan i datafilen.

Först använder vi DBCC IND() för att hitta PagePID:

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

Resultat (med vertikal utdata):

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

Detta returnerar två rekord. Vi är intresserade av PageType of 1 (den andra posten). Vi vill ha PagePID från den posten. I det här fallet är PagePID 320 .

Nu kan vi ta det PagePID och använda det i följande:

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

Detta producerar mycket data, men vi är främst intresserade av följande 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                                    

Detta visar att datetime använder en längd på 8 byte och datetime2(3) använder 7 byte när den lagras i en databas.

Så detta förstärker argumenten för att använda datetime2 över datumtid när du designar nya databaser, särskilt om lagringsstorleken är ett problem.


  1. Hämta det senaste kända värdet för varje kolumn i en rad

  2. MySQL - Hur man väljer data efter stränglängd

  3. Korstabellbegränsningar i PostgreSQL

  4. Gruppera efter kolumn och flera rader till en rad flera kolumner