In diesem Artikel betrachte ich die Speichergröße der Zeit Datentyp in SQL Server.
Insbesondere schaue ich mir Folgendes an:
- Dokumentation von Microsoft
- In einer Variablen gespeicherte Daten
- Länge in Bytes mit
DATALENGTH()
- Länge in Bytes mit
DATALENGTH()
nach der Konvertierung in varbinary
- Länge in Bytes mit
- In einer Datenbank gespeicherte Daten
- Länge in Bytes mit
COL_LENGTH()
- Länge in Byte mit
DBCC PAGE()
- Länge in Bytes mit
Microsoft-Dokumentation
Die offizielle Dokumentation von Microsoft zur Zeit Datentyp gibt an, dass seine Speichergröße zwischen 3 und 5 Bytes liegt, abhängig von der verwendeten Genauigkeit.
Dieser Datentyp ermöglicht eine benutzerdefinierte Genauigkeit. Sie können time(n) verwenden um die Genauigkeit anzugeben, wobei n ist eine Skala zwischen 0 und 7.
Hier sind die Daten, die Microsoft für die Zeit präsentiert Datentyp:
Angegebener Maßstab | Ergebnis (Präzision, Skalierung) | Spaltenlänge (Bytes) | Präzision in Sekundenbruchteilen |
---|---|---|---|
Zeit | (16,7) | 5 | 7 |
Zeit(0) | (8,0) | 3 | 0-2 |
Zeit(1) | (10,1) | 3 | 0-2 |
Zeit(2) | (11,2) | 3 | 0-2 |
Zeit(3) | (12,3) | 4 | 3-4 |
Zeit(4) | (13,4) | 4 | 3-4 |
Zeit(5) | (14,5) | 5 | 5-7 |
Zeit(6) | (15,6) | 5 | 5-7 |
Zeit(7) | (16,7) | 5 | 5-7 |
Für die Zwecke dieses Artikels interessiere ich mich hauptsächlich für die Spaltenlänge (Bytes) Säule. Dies sagt uns, wie viele Bytes verwendet werden, um diesen Datentyp in einer Datenbank zu speichern.
Aus Nutzersicht die Zeit Der Datentyp funktioniert genauso wie der Zeitteil von datetime2 . Es hat eine benutzerdefinierte Genauigkeit in Sekundenbruchteilen und akzeptiert eine Skala von 0 bis 7.
Der Rest dieses Artikels führt durch verschiedene Beispiele, in denen ich die Speichergröße von time zurückgebe Werte in verschiedenen Kontexten.
In einer Variablen gespeicherte Daten
Zuerst speichere ich eine Zeit Wert in einer Variablen und überprüfen Sie ihre Speichergröße. Dann konvertiere ich diesen Wert in varbinary und überprüfe es erneut.
Länge in Bytes mit DATALENGTH
Folgendes passiert, wenn wir DATALENGTH()
verwenden Funktion, um die Anzahl der für eine Zeit(7) verwendeten Bytes zurückzugeben Wert:
DECLARE @t time(7); SET @t = '10:15:30.1234567'; SELECT @t AS 'Value', DATALENGTH(@t) AS 'Length in Bytes';
Ergebnis
+------------------+-------------------+ | Value | Length in Bytes | |------------------+-------------------| | 10:15:30.1234567 | 5 | +------------------+-------------------+
Der Wert in diesem Beispiel hat die maximale Skalierung von 7 (weil ich die Variable als time(7) deklariere ) und gibt eine Länge von 5 Bytes zurück.
Dies ist zu erwarten, da es der in der Tabelle von Microsoft angegebenen Speichergröße entspricht.
Wenn wir den Wert jedoch in varbinary umwandeln wir erhalten ein anderes Ergebnis.
Länge in Bytes nach der Konvertierung in „varbinary“
Einige Entwickler konvertieren gerne Zeit oder datetime2 Variablen in varbinary weil es repräsentativer dafür ist, wie SQL Server es in der Datenbank speichert. Obwohl dies teilweise zutrifft, stimmen die Ergebnisse nicht genau mit dem gespeicherten Wert überein (mehr dazu weiter unten).
Folgendes passiert, wenn wir unsere Zeit umrechnen Wert auf varbinary :
DECLARE @t time(7); SET @t = '10:15:30.1234567'; SELECT CONVERT(VARBINARY(16), @t) AS 'Value', DATALENGTH(CONVERT(VARBINARY(16), @t)) AS 'Length in Bytes';
Ergebnis
+----------------+-------------------+ | Value | Length in Bytes | |----------------+-------------------| | 0x0787A311FC55 | 6 | +----------------+-------------------+
In diesem Fall erhalten wir 6 Bytes. Unser Wert verwendet jetzt 1 Byte mehr als in der Dokumentation angegeben.
Das liegt daran, dass ein zusätzliches Byte benötigt wird, um die Genauigkeit zu speichern.
Dies ist eine hexadezimale Darstellung der Zeit Wert. Der tatsächliche Zeitwert (und seine Genauigkeit) ist alles nach dem 0x
. Jedes Paar Hexadezimalzeichen ist ein Byte. Es gibt 6 Paare und daher 6 Bytes. Dies wird bestätigt, wenn wir DATALENGTH()
verwenden um die Länge in Bytes zurückzugeben.
In diesem Beispiel sehen wir, dass das erste Byte 07
ist . Dies stellt die Genauigkeit dar (ich habe eine Skala von 7 verwendet und das wird hier angezeigt).
Wenn ich die Skalierung ändere, können wir sehen, dass sich das erste Byte ändert, um der Skalierung zu entsprechen:
DECLARE @t time(3); SET @t = '10:15:30.1234567'; SELECT CONVERT(VARBINARY(16), @t) AS 'Value', DATALENGTH(CONVERT(VARBINARY(16), @t)) AS 'Length in Bytes';
Ergebnis
+--------------+-------------------+ | Value | Length in Bytes | |--------------+-------------------| | 0x034B823302 | 5 | +--------------+-------------------+
Wir können auch sehen, dass die Länge entsprechend reduziert wird. Aber auch hier ist es ein Byte mehr als in der Dokumentation angegeben.
Obwohl Microsofts Dokumentation für Zeit erwähnt dies nicht explizit, die Dokumentation zu datetime2 besagt Folgendes:
Das erste Byte eines datetime2 value speichert die Genauigkeit des Werts, d. h. den tatsächlichen Speicherbedarf für ein datetime2 Wert ist die in der obigen Tabelle angegebene Speichergröße plus 1 zusätzliches Byte zum Speichern der Genauigkeit. Dies ergibt die maximale Größe eines datetime2 Wert 9 Byte – 1 Byte speichert die Genauigkeit plus 8 Byte für die Datenspeicherung mit maximaler Genauigkeit.
Und die datetime2 Der Datentyp funktioniert in Bezug auf die obigen Beispiele genauso. Mit anderen Worten, es meldet das zusätzliche Byte nur, wenn es in varbinary konvertiert wird .
Das in der Microsoft-Dokumentation erwähnte zusätzliche Byte scheint also auch für Zeit zu gelten .
Allerdings ist die tatsächliche Speichergröße Ihrer Zeit Werte werden dort angezeigt, wo die Daten gespeichert sind.
In einer Datenbank gespeicherte Daten
Wenn eine Datenbankspalte einen Typ Zeit hat , seine Genauigkeit wird auf Spaltenebene angegeben – nicht auf Datenebene. Mit anderen Worten, es wird einmal für die gesamte Spalte angegeben. Das ist sinnvoll, denn wenn Sie eine Spalte als time(7) definieren , wissen Sie, dass alle Zeilen time(7) sein werden . Keine Notwendigkeit, wertvolle Bytes zu verbrauchen, die diese Tatsache in jeder Zeile wiederholen.
Wenn Sie eine Zeit untersuchen -Wert, da er in SQL Server gespeichert ist, sehen Sie, dass er mit varbinary identisch ist Ergebnis, aber ohne die Präzision.
Nachfolgend finden Sie Beispiele, die zeigen, wie Zeit Werte werden in SQL Server gespeichert.
In diesen Beispielen erstelle ich eine Datenbank mit verschiedenen Zeit(en) Spalten und verwenden Sie dann COL_LENGTH()
um die Länge jeder Spalte in Bytes zurückzugeben. Ich füge dann Werte in diese Spalten ein, bevor ich DBCC PAGE
verwende um die Speichergröße mal zu überprüfen Wert nimmt die Auslagerungsdatei auf.
Erstellen Sie eine Datenbank:
CREATE DATABASE Test;
Erstellen Sie eine Tabelle:
USE Test; CREATE TABLE TimeTest ( t0 time(0), t1 time(1), t2 time(2), t3 time(3), t4 time(4), t5 time(5), t6 time(6), t7 time(7) );
In diesem Fall erstelle ich acht Spalten – eine für jede benutzerdefinierte Skala, die wir mit time(n) verwenden können .
Jetzt können wir die Speichergröße jeder Spalte überprüfen.
Länge in Bytes mit COL_LENGTH()
Verwenden Sie COL_LENGTH()
um die Länge (in Bytes) jeder Spalte zu überprüfen:
SELECT COL_LENGTH ( 'TimeTest' , 't0' ) AS 't0', COL_LENGTH ( 'TimeTest' , 't1' ) AS 't1', COL_LENGTH ( 'TimeTest' , 't2' ) AS 't2', COL_LENGTH ( 'TimeTest' , 't3' ) AS 't3', COL_LENGTH ( 'TimeTest' , 't4' ) AS 't4', COL_LENGTH ( 'TimeTest' , 't5' ) AS 't5', COL_LENGTH ( 'TimeTest' , 't6' ) AS 't6', COL_LENGTH ( 'TimeTest' , 't7' ) AS 't7';
Ergebnis:
+------+------+------+------+------+------+------+------+ | t0 | t1 | t2 | t3 | t4 | t5 | t6 | t7 | |------+------+------+------+------+------+------+------| | 3 | 3 | 3 | 4 | 4 | 5 | 5 | 5 | +------+------+------+------+------+------+------+------+
Wir erhalten also noch einmal das gleiche Ergebnis, das die Dokumentation besagt, dass wir es bekommen werden. Dies ist zu erwarten, da in der Dokumentation ausdrücklich „Spaltenlänge (Bytes)“ angegeben ist, was wir hier genau messen.
Denken Sie daran, dies ist vorher Wir fügen beliebige Daten ein. Die Spalten selbst bestimmen die Genauigkeit (und damit die Speichergröße) aller eingefügten Daten – nicht umgekehrt.
Verwenden Sie DBCC PAGE, um die gespeicherten Daten zu überprüfen
Lassen Sie uns nun Daten einfügen und dann DBCC PAGE
verwenden um die tatsächliche Speichergröße der Daten zu ermitteln, die wir in jeder Spalte speichern.
Daten einfügen:
DECLARE @t time(7) = '10:15:30.1234567'; INSERT INTO TimeTest ( t0, t1, t2, t3, t4, t5, t6, t7 ) SELECT @t, @t, @t, @t, @t, @t, @t, @t;
Wählen Sie nun die Daten aus (nur zur Kontrolle):
SELECT * FROM TimeTest;
Ergebnis (bei vertikaler Ausgabe):
t0 | 10:15:30 t1 | 10:15:30.1000000 t2 | 10:15:30.1200000 t3 | 10:15:30.1230000 t4 | 10:15:30.1235000 t5 | 10:15:30.1234600 t6 | 10:15:30.1234570 t7 | 10:15:30.1234567
Wie erwartet verwenden die Werte die Genauigkeit, die zuvor auf Spaltenebene angegeben wurde.
Beachten Sie, dass mein System nachgestellte Nullen anzeigt. Ihre kann dies tun oder auch nicht. Unabhängig davon hat dies keinen Einfluss auf die tatsächliche Präzision oder Genauigkeit.
Nun, bevor wir DBCC PAGE()
verwenden , müssen wir wissen, welche PagePID an sie übergeben werden soll. Wir können DBCC IND()
verwenden um das zu finden.
Suchen Sie die PagePID:
DBCC IND('Test', 'dbo.TimeTest', 0);
Ergebnis (bei vertikaler Ausgabe):
-[ RECORD 1 ]------------------------- PageFID | 1 PagePID | 308 IAMFID | NULL IAMPID | NULL ObjectID | 1541580530 IndexID | 0 PartitionNumber | 1 PartitionID | 72057594043236352 iam_chain_type | In-row data PageType | 10 IndexLevel | NULL NextPageFID | 0 NextPagePID | 0 PrevPageFID | 0 PrevPagePID | 0 -[ RECORD 2 ]------------------------- PageFID | 1 PagePID | 384 IAMFID | 1 IAMPID | 308 ObjectID | 1541580530 IndexID | 0 PartitionNumber | 1 PartitionID | 72057594043236352 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 384 .
Jetzt können wir diese PagePID nehmen und sie im Folgenden verwenden:
DBCC TRACEON(3604, -1); DBCC PAGE(Test, 1, 384, 3);
Im Moment interessiert uns hauptsächlich der folgende Teil:
Slot 0 Column 1 Offset 0x4 Length 3 Length (physical) 3 t0 = 10:15:30 Slot 0 Column 2 Offset 0x7 Length 3 Length (physical) 3 t1 = 10:15:30.1 Slot 0 Column 3 Offset 0xa Length 3 Length (physical) 3 t2 = 10:15:30.12 Slot 0 Column 4 Offset 0xd Length 4 Length (physical) 4 t3 = 10:15:30.123 Slot 0 Column 5 Offset 0x11 Length 4 Length (physical) 4 t4 = 10:15:30.1235 Slot 0 Column 6 Offset 0x15 Length 5 Length (physical) 5 t5 = 10:15:30.12346 Slot 0 Column 7 Offset 0x1a Length 5 Length (physical) 5 t6 = 10:15:30.123457 Slot 0 Column 8 Offset 0x1f Length 5 Length (physical) 5 t7 = 10:15:30.1234567
Wir erhalten also das gleiche Ergebnis wie in der Dokumentation angegeben. Dies würde darauf hindeuten, dass die Genauigkeit nicht mit den Werten gespeichert wird.
Wir können dies bestätigen, indem wir die tatsächlichen Daten untersuchen.
Die tatsächlichen Zeitwerte werden in diesem Teil der Auslagerungsdatei gespeichert:
Memory Dump @0x0000000423ADA060 0000000000000000: 10002400 42900095 a205d459 384b8233 02f31603 ..$.B..¢.ÔY8K3.ó.. 0000000000000014: 167ae51e dc00c1f6 34990887 a311fc55 080000 .zå.Ü.Áö4..£.üU...
Wir können die tatsächlichen Zeitwerte extrahieren, indem wir ein paar Dinge entfernen. Nach dem Entfernen bleibt Folgendes bestehen:
42900095 a205d459 384b8233 02f31603 167ae51e dc00c1f6 34990887 a311fc55
Diese Hex-Ziffern enthalten alle unsere Zeitdaten, aber nicht die Genauigkeit . Sie sind jedoch in 4-Byte-Blöcke angeordnet, sodass wir die Leerzeichen neu anordnen müssen, um die einzelnen Werte zu erhalten.
Hier ist das Endergebnis. Zur besseren Lesbarkeit habe ich jeden Datums-/Uhrzeitwert in eine neue Zeile eingefügt.
429000 95a205 d45938 4b823302 f3160316 7ae51edc00 c1f6349908 87a311fc55
Das sind die tatsächlichen Hexadezimalwerte (abzüglich der Genauigkeit ), die wir erhalten würden, wenn wir die Zeit umwandeln würden Wert auf varbinary . So:
SELECT CONVERT(VARBINARY(16), t0) AS 't0', CONVERT(VARBINARY(16), t1) AS 't1', CONVERT(VARBINARY(16), t2) AS 't2', CONVERT(VARBINARY(16), t3) AS 't3', CONVERT(VARBINARY(16), t4) AS 't4', CONVERT(VARBINARY(16), t5) AS 't5', CONVERT(VARBINARY(16), t6) AS 't6', CONVERT(VARBINARY(16), t7) AS 't7' FROM TimeTest;
Ergebnis (bei vertikaler Ausgabe):
t0 | 0x00429000 t1 | 0x0195A205 t2 | 0x02D45938 t3 | 0x034B823302 t4 | 0x04F3160316 t5 | 0x057AE51EDC00 t6 | 0x06C1F6349908 t7 | 0x0787A311FC55
Diese Abfrage liefert das gleiche Ergebnis – außer dass jedem Wert die Genauigkeit vorangestellt wurde.
Hier ist eine Tabelle, die die tatsächlichen Daten der Auslagerungsdatei mit den Ergebnissen von CONVERT()
vergleicht Betrieb.
Auslagerungsdateidaten | CONVERT()-Daten |
---|---|
429000 | 00429000 |
95a205 | 0195A205 |
d45938 | 02D45938 |
4b823302 | 034B823302 |
f3160316 | 04F3160316 |
7ae51edc00 | 057AE51EDC00 |
c1f6349908 | 06C1F6349908 |
87a311fc55 | 0787A311FC55 |
Wir können also sehen, dass die Auslagerungsdatei die Genauigkeit nicht speichert, aber das konvertierte Ergebnis.
Ich habe die tatsächlichen Datums- und Uhrzeitteile rot hervorgehoben. Ich habe auch das 0x
entfernt Präfix aus den konvertierten Ergebnissen, sodass nur die tatsächlichen Datums-/Uhrzeitdaten angezeigt werden (zusammen mit der Genauigkeit).
Beachten Sie auch, dass bei Hexadezimalzahlen die Groß- und Kleinschreibung nicht beachtet wird, sodass die Tatsache, dass der eine Kleinbuchstaben und der andere Großbuchstaben verwendet, kein Problem darstellt.
Schlussfolgerung
Beim Umrechnen einer Zeit Wert auf varbinary , benötigt es ein zusätzliches Byte, um die Genauigkeit zu speichern. Es benötigt die Genauigkeit, um den Zeitabschnitt zu interpretieren (weil dies als Zeitintervall gespeichert wird, dessen genauer Wert von der Genauigkeit abhängt).
Beim Speichern in einer Datenbank wird die Genauigkeit einmal auf Spaltenebene angegeben. Dies erscheint logisch, da die Genauigkeit nicht jeder Zeile hinzugefügt werden muss, wenn alle Zeilen sowieso die gleiche Genauigkeit haben. Das würde ein zusätzliches Byte für jede Zeile erfordern, was den Speicherbedarf unnötig erhöhen würde.