Tento článek zkoumá hlavní rozdíly mezi datetime2 a smalldatetime datové typy na serveru SQL.
Oba datové typy se používají pro ukládání hodnot data a času, nicméně mezi nimi jsou některé důležité rozdíly. Ve většině případů je lepší použít datetime2 (Microsoft to také doporučuje), mohou však existovat některé scénáře, kdy budete muset použít smalldatetime .
Zde je tabulka, která uvádí hlavní rozdíly mezi těmito dvěma typy.
Funkce | smalldatetime | datetime2 |
---|---|---|
Vyhovující SQL (ANSI &ISO 8601) | Ne | Ano |
Časové období | 1900-01-01 až 2079-06-06 | 0001-01-01 až 9999-12-31 |
Časový rozsah | 00:00:00 až 23:59:59 | 00:00:00 až 23:59:59.9999999 |
Délka znaků | Maximálně 19 pozic | Minimálně 19 pozic Maximálně 27 |
Velikost úložiště | 4 bajty, opraveno | 6 až 8 bajtů, v závislosti na přesnosti* * Plus 1 bajt pro uložení přesnosti |
Přesnost | Jedna minuta | 100 nanosekund |
Zlomková sekundová přesnost | Ne | Ano |
Uživatelsky definovaná přesnost na zlomek sekund | Ne | Ano |
Posun časového pásma | Žádné | Žádné |
Sledování a zachování posunu časového pásma | Ne | Ne |
Sledování letního času | Ne | Ne |
Výhody ‚datetime2‘
Jak je vidět v tabulce výše, datetime2 typ má mnoho výhod oproti smalldatetime , včetně:
- větší časové období
- přesnost na zlomky sekund
- volitelná přesnost zadaná uživatelem
- vyšší přesnost
- je v souladu se standardy SQL (ANSI a ISO 8601)
* V některých případech datetime2 value používá k uložení přesnosti bajt navíc, ale když je uložena v databázi, je přesnost zahrnuta do definice sloupce, takže skutečná uložená hodnota nevyžaduje bajt navíc.
Mám použít „datetime“ nebo „smalldatetime“?
Společnost Microsoft doporučuje datetime2 pro novou práci (a ze stejných důvodů uvedených výše).
Proto byste měli použít datetime2 , pokud k tomu nemáte konkrétní důvod (například práce se starším systémem).
Příklad 1 – Základní srovnání
Zde je rychlý příklad demonstrující základní rozdíl mezi datetime2 a smalldatetime .
DECLARE @thedatetime2 datetime2(7), @thesmalldatetime smalldatetime; SET @thedatetime2 = '2025-05-21 10:15:30.5555555'; SET @thesmalldatetime = @thedatetime2; SELECT @thedatetime2 AS 'datetime2', @thesmalldatetime AS 'smalldatetime';
Výsledek:
+-----------------------------+---------------------+ | datetime2 | smalldatetime | |-----------------------------+---------------------| | 2025-05-21 10:15:30.5555555 | 2025-05-21 10:16:00 | +-----------------------------+---------------------+
Zde nastavím smalldatetime proměnnou na stejnou hodnotu jako datetime2 variabilní. To způsobí, že se hodnota převede na smalldatetime a pak můžeme použít SELECT
pro zobrazení hodnoty každé proměnné.
V tomto případě datetime2 proměnná používá stupnici 7, což znamená, že má 7 desetinných míst. smalldatetime hodnotu na druhé straně nemá žádnou desetinná místa. Kromě toho jsou jeho sekundy nastaveny na nulu a jeho minuty jsou zaokrouhleny nahoru.
Dá se to očekávat, protože oficiální dokumentace společnosti Microsoft uvádí, že smalldatetime
Čas je založen na 24hodinovém dni, přičemž sekundy jsou vždy nula (:00) a bez zlomků sekund
.
Takže vidíme, že datetime2 type poskytuje mnohem přesnější a přesnější hodnotu data/času.
Samozřejmě možná nebudete potřebovat všechny ty zlomkové sekundy. Jedna z dobrých věcí na datetime2 je, že můžete určit, kolik (pokud vůbec) zlomkových sekund chcete.
Příklad 2 – Použití méně desetinných míst
V tomto příkladu zmenšuji datetime2 měřítko na 0:
DECLARE @thedatetime2 datetime2(0), @thesmalldatetime smalldatetime; SET @thedatetime2 = '2025-05-21 10:15:30.5555555'; SET @thesmalldatetime = @thedatetime2; SELECT @thedatetime2 AS 'datetime2', @thesmalldatetime AS 'smalldatetime';
Výsledek:
+---------------------+---------------------+ | datetime2 | smalldatetime | |---------------------+---------------------| | 2025-05-21 10:15:31 | 2025-05-21 10:16:00 | +---------------------+---------------------+
V tomto případě datetime2 hodnota již nezahrnuje zlomkovou část. Oba typy nyní sdílejí stejnou délku znaků (19 pozic).
Ale stále existují rozdíly.
datetime2 value respektuje hodnotu sekund, i když v tomto případě byly její sekundy zaokrouhleny nahoru. Jak již bylo zmíněno, smalldatetime složka sekund hodnoty je vždy nastavena na nulu a v tomto případě byly její minuty zaokrouhleny nahoru.
Důvodem je datetime2 sekundová složka je zaokrouhlena nahoru, protože zlomková část je 5 nebo vyšší. Zmenšíme-li zlomkovou část, žádné zaokrouhlení se neprovede:
DECLARE @thedatetime2 datetime2(0), @thesmalldatetime smalldatetime; SET @thedatetime2 = '2025-05-21 10:15:30.4444444'; SET @thesmalldatetime = @thedatetime2; SELECT @thedatetime2 AS 'datetime2', @thesmalldatetime AS 'smalldatetime';
Výsledek:
+---------------------+---------------------+ | datetime2 | smalldatetime | |---------------------+---------------------| | 2025-05-21 10:15:30 | 2025-05-21 10:16:00 | +---------------------+---------------------+
Nicméně smalldatetime minuty hodnoty se nadále zaokrouhlují nahoru.
Příklad 3 – Nastavení hodnot z řetězcových literálů
V předchozích příkladech smalldatetime hodnota byla přiřazena nastavením na stejnou hodnotu jako datetime2 hodnota. Když to uděláme, SQL Server provede implicitní převod, aby data „seděla“ novému datovému typu.
Pokud se však pokusíme přiřadit stejný řetězcový literál k smalldatetime proměnné, dostaneme chybu:
DECLARE @thedatetime2 datetime2(0), @thesmalldatetime smalldatetime SET @thedatetime2 = '2025-05-21 10:15:30.4444444' SET @thesmalldatetime = '2025-05-21 10:15:30.4444444' SELECT @thedatetime2 AS 'datetime2', @thesmalldatetime AS 'smalldatetime';
Výsledek:
Msg 295, Level 16, State 3, Line 5 Conversion failed when converting character string to smalldatetime data type.
Důvodem je smalldatetime přijímá pouze řetězcové literály, které mají 3 nebo méně zlomkových sekund.
Můžete očekávat, že nebude akceptovat řetězcové literály s any zlomkové sekundy, protože nezahrnuje zlomkové sekundy, ale není tomu tak. S radostí přijímá 3 zlomkové sekundy, ale ne více.
Abychom tento problém překonali, musíme zmenšit zlomkovou část na pouhá 3 (nebo méně) desetinná místa.
DECLARE @thedatetime2 datetime2(0), @thesmalldatetime smalldatetime; SET @thedatetime2 = '2025-05-21 10:15:30.4444444'; SET @thesmalldatetime = '2025-05-21 10:15:30.444'; SELECT @thedatetime2 AS 'datetime2', @thesmalldatetime AS 'smalldatetime';
Výsledek:
+---------------------+---------------------+ | datetime2 | smalldatetime | |---------------------+---------------------| | 2025-05-21 10:15:30 | 2025-05-21 10:16:00 | +---------------------+---------------------+
datetime2 typ nemá toto omezení, a to ani při použití stupnice 0.
Příklad 4 – Velikost úložiště
smalldatetime datový typ má pevnou velikost úložiště 4 bajty. Toto je jedna z mála výhod smalldatetime má více než datetime2 .
datetime2 může mít buď 6, 7 nebo 8 bajtů, v závislosti na jeho přesnosti. Tedy datetime2 hodnota bude vždy využívat alespoň o 2 bajty více úložiště než smalldatetime hodnotu.
Microsoft uvádí, že datetime2 type také používá 1 bajt navíc k uložení své přesnosti, v takovém případě by použil alespoň o 3 bajty více než smalldatetime .
To však pravděpodobně závisí na tom, zda ji ukládáme do tabulky nebo do proměnné a zda ji převádíme na binární konstantu.
Zde je to, co se stane, když použijeme DATALENGTH()
funkce, která vrátí počet bajtů použitých pro každou z našich hodnot:
DECLARE @thedatetime2 datetime2(0), @thesmalldatetime smalldatetime; SET @thedatetime2 = '2025-05-21 10:15:30'; SET @thesmalldatetime = @thedatetime2; SELECT DATALENGTH(@thedatetime2) AS 'datetime2', DATALENGTH(@thesmalldatetime) AS 'smalldatetime';
Výsledek
+-------------+-----------------+ | datetime2 | smalldatetime | |-------------+-----------------| | 6 | 4 | +-------------+-----------------+
Pokud je ale převedeme na varbinární , dostaneme následující:
DECLARE @thedatetime2 datetime2(0), @thesmalldatetime smalldatetime; SET @thedatetime2 = '2025-05-21 10:15:30'; SET @thesmalldatetime = @thedatetime2; SELECT DATALENGTH(CAST(@thedatetime2 AS varbinary(10))) AS 'datetime2', DATALENGTH(CAST(@thesmalldatetime AS varbinary(10))) AS 'smalldatetime';
Výsledek
+-------------+-----------------+ | datetime2 | smalldatetime | |-------------+-----------------| | 7 | 4 | +-------------+-----------------+
Takže datetime2 používá při převodu na varbinary bajt navíc . Mnoho vývojářů předpokládá, že převod na varbinary je reprezentativní pro to, jak SQL Server skutečně ukládá hodnoty data a času.
To je ovšem pravda jen částečně. I když je pravda, že SQL Server ukládá své hodnoty data a času v šestnáctkové soustavě, tato hexadecimální hodnota ve skutečnosti nezahrnuje přesnost. Je to proto, že přesnost je zahrnuta v definici sloupce. Ale když převedeme na varbinary stejně jako v předchozím příkladu je předřazena přesnost, což přidává další bajt.
Následující příklad to ukazuje. Ukazuje, že když jsou data uložena ve sloupci databáze, získáme délku 6 bajtů pro datetime2 vs 4 bajty pro smalldatetime .
Příklad 5 – Velikost úložiště pro uložená data
V tomto příkladu vytvořím databázi a použiji COL_LENGTH
vrátit délku každého sloupce v bajtech. Poté vložím datetime2 a smalldatetime do něj a použijte DBCC PAGE()
zjistit délku skutečných dat v souboru stránky. To nám ukazuje úložný prostor, který jednotlivé typy dat využívají, když jsou uloženy v databázi.
Vytvořte databázi:
CREATE DATABASE CompareTypes;
Vytvořte tabulku:
USE CompareTypes; CREATE TABLE Datetime2vsSmalldatetime ( TheDateTime2 datetime2(0), TheSmallDateTime smalldatetime );
V tomto případě vytvořím dva sloupce – jeden je datetime2(0) a druhý je smalldatetime sloupec.
Zkontrolujte délku sloupce
Zkontrolujte délku (v bajtech) každého sloupce:
SELECT COL_LENGTH ( 'dbo.Datetime2vsSmalldatetime' , 'TheDateTime2' ) AS 'datetime2', COL_LENGTH ( 'dbo.Datetime2vsSmalldatetime' , 'TheSmallDateTime' ) AS 'smalldatetime';
Výsledek:
+-------------+-----------------+ | datetime2 | smalldatetime | |-------------+-----------------| | 6 | 4 | +-------------+-----------------+
Vidíme tedy, že datetime2(0) sloupec má délku 6 bajtů ve srovnání s smalldatetime s délkou 4 bajtů.
Vložit data
Nyní se podívejme na velikost úložiště skutečných hodnot data a času, když jsou uloženy na serveru SQL. Můžeme použít DBCC PAGE()
zkontrolovat skutečnou stránku v datovém souboru.
Nejprve však musíme do našich sloupců vložit data.
Vložit data:
DECLARE @thedatetime2 datetime2 = '2025-05-21 10:15:30'; INSERT INTO Datetime2vsSmalldatetime ( TheSmallDateTime, TheDateTime2 ) SELECT @thedatetime2, @thedatetime2;
Vyberte data (jen pro kontrolu):
SELECT * FROM Datetime2vsSmalldatetime;
Výsledek:
+---------------------+---------------------+ | TheDateTime2 | TheSmallDateTime | |---------------------+---------------------| | 2025-05-21 10:15:30 | 2025-05-21 10:16:00 | +---------------------+---------------------+
Použití DBCC PAGE()
Zde používáme DBCC PAGE()
zkontrolovat skutečnou stránku v datovém souboru.
Nejprve použijeme DBCC IND()
k nalezení PagePID:
DBCC IND('CompareTypes', 'dbo.Datetime2vsSmalldatetime', 0);
Výsledek (při použití vertikálního výstupu):
-[ RECORD 1 ]------------------------- PageFID | 1 PagePID | 308 IAMFID | NULL IAMPID | NULL ObjectID | 1205579333 IndexID | 0 PartitionNumber | 1 PartitionID | 72057594043039744 iam_chain_type | In-row data PageType | 10 IndexLevel | NULL NextPageFID | 0 NextPagePID | 0 PrevPageFID | 0 PrevPagePID | 0 -[ RECORD 2 ]------------------------- PageFID | 1 PagePID | 344 IAMFID | 1 IAMPID | 308 ObjectID | 1205579333 IndexID | 0 PartitionNumber | 1 PartitionID | 72057594043039744 iam_chain_type | In-row data PageType | 1 IndexLevel | 0 NextPageFID | 0 NextPagePID | 0 PrevPageFID | 0 PrevPagePID | 0
Tím se vrátí dva záznamy. Zajímá nás PageType 1 (druhý záznam). Chceme PagePID z tohoto záznamu. V tomto případě je PagePID 344 .
Nyní můžeme vzít toto PagePID a použít jej v následujícím:
DBCC TRACEON(3604, -1); DBCC PAGE(CompareTypes, 1, 344, 3);
To produkuje spoustu dat, ale nás zajímá hlavně následující část:
Slot 0 Column 1 Offset 0x4 Length 6 Length (physical) 6 TheDateTime2 = 2025-05-21 10:15:30 Slot 0 Column 2 Offset 0xa Length 4 Length (physical) 4 TheSmallDateTime = 2025-05-21 10:16:00.000
To ukazuje, že smalldatetime má délku 4 bajty a datetime2(0) má při uložení v databázi 6 bajtů.
V tomto případě je tedy rozdíl pouze 2 bajty, ale datetime2(0) je přesnější a dodržuje normy ANSI a ISO 8601.