Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

datetime vs datetime2 in SQL Server:Was ist der Unterschied?

In diesem Artikel werden die Hauptunterschiede zwischen datetime untersucht und datetime2 Datentypen in SQL Server.

Wenn Sie sich nicht sicher sind, welches Sie verwenden sollen, verwenden Sie datetime2 (siehe seine Vorteile unten).

Hier ist eine Tabelle, die die Hauptunterschiede zwischen diesen beiden Typen umreißt.

Funktion datetime datetime2
SQL-konform (ANSI &ISO 8601) Nein Ja
Zeitraum 1753-01-01 bis 9999-12-31 0001-01-01 bis 9999-12-31
Zeitbereich 00:00:00 bis 23:59:59.997 00:00:00 bis 23:59:59.9999999
Zeichenlänge mindestens 19 Positionen
maximal 23
mindestens 19 Positionen
maximal 27
Speichergröße 8 Byte 6 bis 8 Byte, je nach Genauigkeit*

* Plus 1 Byte zum Speichern der Genauigkeit

Genauigkeit Gerundet auf 0,000, 0,003 oder 0,007 Sekunden 100 Nanosekunden
Benutzerdefinierte Genauigkeit für Sekundenbruchteile Nein Ja
Zeitzonenverschiebung Keine Keine
Bewusstsein und Erhaltung der Zeitzonenverschiebung Nein Nein
Sommerzeit bewusst Nein Nein

Vorteile von ‚datetime2‘

Wie in der obigen Tabelle zu sehen, ist die datetime2 type hat viele Vorteile gegenüber datetime , einschließlich:

  • größerer Datumsbereich
  • größere standardmäßige Bruchgenauigkeit
  • optionale benutzerdefinierte Genauigkeit
  • höhere Genauigkeit, selbst bei Verwendung der gleichen Anzahl von Dezimalstellen wie datetime (d.h. 3)
  • weniger Speichergröße bei Verwendung der gleichen Anzahl an Dezimalstellen wie datetime , jedoch mit höherer Genauigkeit*
  • die Option, 2 Bytes weniger Speicherplatz zu verwenden als datetime (allerdings mit geringerer Genauigkeit)*
  • richtet sich an den SQL-Standards (ANSI &ISO 8601)

* In manchen Fällen ein datetime2 value verwendet ein zusätzliches Byte, um die Genauigkeit zu speichern, was zu derselben Speichergröße wie datetime führen würde bei Verwendung der gleichen Anzahl von Nachkommastellen. Lesen Sie weiter, um mehr darüber zu erfahren.

Soll ich „datetime“ oder „datetime2“ verwenden?

Microsoft empfiehlt datetime2 über datetime für neue Arbeiten (und aus denselben oben aufgeführten Gründen).

Daher sollten Sie datetime2 verwenden , es sei denn, Sie haben einen bestimmten Grund, dies nicht zu tun (z. B. die Arbeit mit einem Legacy-System).

Beispiel 1 – Grundlegender Vergleich

Hier ist ein kurzes Beispiel, um den grundlegenden Unterschied zwischen datetime zu demonstrieren und 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';

Ergebnis:

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

Hier setze ich eine datetime Variable auf den gleichen Wert wie datetime2 Variable. Dadurch wird der Wert in datetime konvertiert und wir können dann ein SELECT verwenden Anweisung, um das Ergebnis zu sehen.

In diesem Fall datetime2 Variable verwendet eine Skala von 7, was 7 Dezimalstellen bedeutet. Die datetime -Wert hingegen verwendet nur 3 Dezimalstellen, und seine letzte Nachkommastelle wird aufgerundet (weil dieser Datentyp die Sekundenbruchteile in Schritten von 0,000, 0,003 oder 0,007 Sekunden rundet).

Beispiel 2 – Verwendung von 3 Dezimalstellen

Wenn ich die datetime2 reduziere auf 3 skalieren (entsprechend dateime ), Folgendes passiert.

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

Ergebnis:

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

Also datetime2 Wert wird auch in diesem Fall aufgerundet. Es wird jedoch nur auf 556 aufgerundet – es springt nicht auf 557 wie datetime Wert tut.

Der einzige Grund ist natürlich datetime2 Der Wert wird aufgerundet, weil die folgende Ziffer 5 oder höher ist. Wenn wir die folgende Ziffer reduzieren, wird nicht gerundet:

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

Ergebnis:

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

Die datetime Wert wird weiterhin aufgerundet.

Beispiel 3 – Setzen von Werten aus String-Literalen

In den vorherigen Beispielen wurde die Datei dateime value wurde zugewiesen, indem es auf den gleichen Wert wie datetime2 gesetzt wurde Wert. Wenn wir das tun, führt SQL Server eine implizite Konvertierung durch, damit die Daten dem neuen Datentyp „passen“.

Wenn wir jedoch versuchen, datetime dasselbe Zeichenfolgenliteral zuzuweisen Variable, die wir datetime2 zugewiesen haben , erhalten wir einen Fehler:

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

Ergebnis:

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

Das liegt daran, dass datetime akzeptiert nur Zeichenfolgenliterale mit 3 oder weniger Sekundenbruchteilen.

Um dieses Problem zu lösen, müssen wir also den Bruchteil auf nur 3 (oder weniger) Dezimalstellen reduzieren.

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

Ergebnis:

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

Die datetime2 Typ hat diese Einschränkung nicht, selbst wenn eine Skala von 3 verwendet wird.

Beispiel 4 – Speichergröße

Die datetime Datentyp hat eine feste Speichergröße von 8 Bytes.

Die datetime2 andererseits kann es je nach Genauigkeit entweder 6, 7 oder 8 Bytes sein.

Bei Verwendung von 3 Dezimalstellen datetime2 verwendet nur 7 Bytes, was bedeutet, dass es weniger Speicherplatz benötigt als datetime (mit mehr Genauigkeit).

Microsoft gibt jedoch an, dass die datetime2 Typ verwendet auch 1 zusätzliches Byte, um seine Genauigkeit zu speichern. In diesem Fall würde es also 8 Bytes verwenden. Und wir können daher die vorherige Aussage revidieren, indem wir sagen, dass sie entweder 7, 8 oder 9 Bytes verwendet.

Dies hängt jedoch wahrscheinlich davon ab, ob wir es in einer Tabelle oder in einer Variablen speichern und ob wir es in eine binäre Konstante konvertieren oder nicht.

Folgendes passiert, wenn wir DATALENGTH() verwenden Funktion, um die Anzahl der Bytes zurückzugeben, die für jeden unserer Werte verwendet werden:

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

Ergebnis

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

Aber wenn wir sie in varbinary umwandeln , erhalten wir Folgendes:

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

Ergebnis

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

Also datetime2 verwendet ein zusätzliches Byte, wenn es in varbinary konvertiert wird , wodurch es auf die gleiche Speichergröße wie datetime gebracht wird .

Das folgende Beispiel zeigt jedoch, dass wir beim Speichern der Daten in einer Datenbankspalte eine Länge von 7 Bytes für datetime2 erhalten und 8 Bytes für datetime .

Beim Speichern von datetime2 Werten in einer Datenbank enthält die Spaltendefinition die Genauigkeit. In diesem Fall benötigen die Werte in jeder Zeile kein zusätzliches Byte, um die Genauigkeit zu speichern, und wir können sagen, dass datetime2 verbraucht weniger Speicherplatz als datetime wenn die gleiche Anzahl von Sekundenbruchteilen verwendet wird.

Beispiel 5 – Speichergröße für gespeicherte Daten

In diesem Beispiel erstelle ich eine Datenbank und verwende COL_LENGTH um die Länge jeder Spalte in Bytes zurückzugeben. Dann füge ich ein datetime2 ein und datetime Wert hinein und verwenden Sie DBCC PAGE() um die Länge der tatsächlichen Daten in der Auslagerungsdatei zu finden. Dies zeigt uns den Speicherplatz, den jeder Datentyp verwendet, wenn er in einer Datenbank gespeichert wird.

Erstellen Sie eine Datenbank:

CREATE DATABASE CompareTypes;

Erstellen Sie eine Tabelle:

USE CompareTypes;

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

In diesem Fall erstelle ich zwei Spalten – eine ist ein datetime Spalte und die andere ist ein datetime2 Spalte.

Überprüfen Sie die Spaltenlänge

Prüfen Sie die Länge (in Byte) jeder Spalte:

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

Ergebnis:

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

Wir sehen also, dass datetime2 Spalte hat im Vergleich zu datetime eine Länge von 7 Bytes Länge von 8 Bytes.

Daten einfügen

Sehen wir uns nun die Speichergröße der tatsächlichen Datums- und Uhrzeitwerte an, wenn sie in SQL Server gespeichert werden. Wir können DBCC PAGE() verwenden um die aktuelle Seite in der Datendatei zu überprüfen.

Aber zuerst müssen wir Daten in unsere Spalten einfügen.

Daten einfügen:

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

Wählen Sie die Daten aus (nur zur Kontrolle):

SELECT * FROM Datetime2vsDatetime;

Ergebnis:

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

Verwendung von DBCC PAGE()

Hier verwenden wir DBCC PAGE() um die aktuelle Seite in der Datendatei zu überprüfen.

Zuerst verwenden wir DBCC IND() um die PagePID zu finden:

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

Ergebnis (bei vertikaler Ausgabe):

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

Dies gibt zwei Datensätze zurück. Uns interessiert der PageType von 1 (der 2. Datensatz). Wir wollen die PagePID aus diesem Datensatz. In diesem Fall ist die PagePID 320 .

Jetzt können wir diese PagePID nehmen und sie im Folgenden verwenden:

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

Dies erzeugt eine Menge Daten, aber wir interessieren uns hauptsächlich für den folgenden Teil:

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                                    

Dies zeigt diese datetime verwendet eine Länge von 8 Bytes und datetime2(3) verwendet 7 Bytes, wenn es in einer Datenbank gespeichert wird.

Dies bestärkt also die Verwendung von datetime2 über datetime beim Entwerfen neuer Datenbanken, insbesondere wenn die Speichergröße ein Problem darstellt.