Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

datetime vs datetime2 w SQL Server:jaka jest różnica?

W tym artykule omówiono główne różnice między data i godziną i data/godzina2 typy danych w SQL Server.

Jeśli nie masz pewności, którego użyć, użyj datetime2 (zobacz jego zalety poniżej).

Oto tabela przedstawiająca kluczowe różnice między tymi dwoma typami.

Funkcja data i godzina dataczas2
Zgodny z SQL (ANSI i ISO 8601) Nie Tak
Zakres dat 1753-01-01 do 9999-12-31 0001-01-01 do 9999-12-31
Zakres czasu 00:00:00 do 23:59:59,997 00:00:00 do 23:59:59,999999
Długość znaku Minimalnie 19 pozycji
Maksymalnie 23
Minimum 19 pozycji
Maksimum 27
Rozmiar pamięci 8 bajtów 6 do 8 bajtów, w zależności od precyzji*

* Plus 1 bajt do przechowywania precyzji

Dokładność Zaokrąglone do przyrostów o 0,000, 0,003 lub 0,007 sekundy 100 nanosekund
Zdefiniowana przez użytkownika precyzja ułamkowa sekundy Nie Tak
Przesunięcie strefy czasowej Brak Brak
Świadomość i zachowanie przesunięcia strefy czasowej Nie Nie
Świadomość czasu letniego Nie Nie

Zalety „datetime2”

Jak widać w powyższej tabeli, datetime2 typ ma wiele zalet w porównaniu z datetime , w tym:

  • większy zakres dat
  • większa domyślna precyzja ułamkowa
  • opcjonalna precyzja określona przez użytkownika
  • większa dokładność, nawet przy użyciu tej samej liczby miejsc dziesiętnych co data i godzina (tj. 3)
  • mniejszy rozmiar pamięci przy użyciu tej samej liczby miejsc dziesiętnych co data-godzina , ale z większą dokładnością*
  • opcja użycia 2 bajtów mniej miejsca niż data-godzina (choć z mniejszą precyzją)*
  • jest zgodny ze standardami SQL (ANSI i ISO 8601)

* W niektórych przypadkach datetime2 value wykorzystuje dodatkowy bajt do przechowywania precyzji, co skutkowałoby tym samym rozmiarem pamięci co data i godzina przy użyciu tej samej liczby miejsc dziesiętnych. Czytaj dalej, aby dowiedzieć się więcej na ten temat.

Czy powinienem używać „datetime” czy „datetime2”?

Microsoft zaleca datetime2 ponad data i godzina do nowej pracy (i z tych samych powodów wymienionych powyżej).

Dlatego powinieneś używać datetime2 , chyba że masz konkretny powód, aby tego nie robić (np. praca ze starszym systemem).

Przykład 1 – Porównanie podstawowe

Oto krótki przykład pokazujący podstawową różnicę między datetime i data/godzina2 .

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

Wynik:

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

Tutaj ustawiam datę zmienna na taką samą wartość jak datetime2 zmienny. Powoduje to przekonwertowanie wartości na data/godzina a następnie możemy użyć SELECT oświadczenie, aby zobaczyć wynik.

W tym przypadku datetime2 zmienna wykorzystuje skalę 7, co oznacza 7 miejsc po przecinku. data i godzina z drugiej strony używa tylko 3 miejsc po przecinku, a ostatnia cyfra ułamkowa jest zaokrąglana w górę (ponieważ ten typ danych zaokrągla sekundy ułamkowe do przyrostów o 0,000, 0,003 lub 0,007 sekundy).

Przykład 2 – użycie 3 miejsc dziesiętnych

Jeśli skrócę datetime2 przeskalować do 3 (aby dopasować datę ), oto co się dzieje.

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

Wynik:

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

Tak więc datetime2 wartość jest również zaokrąglana w tym przypadku. Jednak jest zaokrąglana tylko do 556 – nie skacze do 557 jak data i godzina wartość ma.

Oczywiście jedynym powodem, dla którego datetime2 wartość jest zaokrąglana w górę, ponieważ następna cyfra jest równa 5 lub wyższa. Jeśli zmniejszymy następującą cyfrę, zaokrąglenie nie zostanie wykonane:

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

Wynik:

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

Jednak data i godzina wartość jest nadal zaokrąglana w górę.

Przykład 3 – ustawianie wartości z literałów łańcuchowych

W poprzednich przykładach data wartość została przypisana przez ustawienie jej na taką samą wartość jak datetime2 wartość. Kiedy to robimy, SQL Server wykonuje niejawną konwersję, aby dane „dopasowały się” do nowego typu danych.

Jeśli jednak spróbujemy przypisać ten sam literał ciągu do datetime zmienna, którą przypisaliśmy do datetime2 , pojawia się błąd:

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

Wynik:

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

Dzieje się tak, ponieważ data i godzina akceptuje tylko literały ciągów, które mają 3 lub mniej ułamków sekund.

Aby rozwiązać ten problem, musimy zmniejszyć część ułamkową do zaledwie 3 (lub mniej) miejsc po przecinku.

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

Wynik:

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

data/godzina2 typ nie ma tego ograniczenia, nawet przy użyciu skali 3.

Przykład 4 – Rozmiar pamięci

data i godzina typ danych ma stały rozmiar pamięci wynoszący 8 bajtów.

data/godzina2 z drugiej strony może mieć 6, 7 lub 8 bajtów, w zależności od jego precyzji.

Używając 3 miejsc po przecinku, datetime2 używa tylko 7 bajtów, co oznacza, że ​​zajmuje mniej miejsca niż datetime (z większą dokładnością).

Jednak Microsoft twierdzi, że datetime2 type wykorzystuje również 1 dodatkowy bajt do przechowywania swojej precyzji. Więc w tym przypadku użyje 8 bajtów. I dlatego możemy zrewidować poprzednie stwierdzenie, mówiąc, że używa 7, 8 lub 9 bajtów.

Jednak prawdopodobnie zależy to od tego, czy przechowujemy je w tabeli, czy w zmiennej i czy konwertujemy ją na stałą binarną.

Oto, co się stanie, jeśli użyjemy DATALENGTH() funkcja zwracająca liczbę bajtów użytych dla każdej z naszych wartości:

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

Wynik

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

Ale jeśli przekonwertujemy je na varbinary , otrzymujemy:

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

Wynik

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

A więc datetime2 używa dodatkowego bajtu po konwersji na warbinar , dzięki czemu ma ten sam rozmiar pamięci co data/godzina .

Jednak poniższy przykład pokazuje, że gdy dane są przechowywane w kolumnie bazy danych, otrzymujemy długość 7 bajtów dla datetime2 i 8 bajtów na data i godzina .

Podczas przechowywania datetime2 wartości w bazie danych, definicja kolumny zawiera precyzję. W tym przypadku wartości w każdym wierszu nie potrzebują dodatkowego bajtu do przechowywania precyzji i możemy powiedzieć, że datetime2 zajmuje mniej miejsca niż data i godzina przy użyciu tej samej liczby ułamków sekund.

Przykład 5 – Rozmiar pamięci dla przechowywanych danych

W tym przykładzie tworzę bazę danych i używam COL_LENGTH aby zwrócić długość każdej kolumny w bajtach. Następnie wstawiam datetime2 i data i godzina wartość do niego i użyj DBCC PAGE() aby znaleźć długość rzeczywistych danych w pliku strony. Pokazuje nam to miejsce, w którym każdy typ danych jest przechowywany w bazie danych.

Utwórz bazę danych:

CREATE DATABASE CompareTypes;

Utwórz tabelę:

USE CompareTypes;

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

W tym przypadku tworzę dwie kolumny – jedna to data i godzina kolumna, a druga to datetime2 kolumna.

Sprawdź długość kolumny

Sprawdź długość (w bajtach) każdej kolumny:

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

Wynik:

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

Widzimy więc, że datetime2 kolumna ma długość 7 bajtów w porównaniu z datetime długość 8 bajtów.

Wstaw dane

Przyjrzyjmy się teraz rozmiarowi przechowywania rzeczywistych wartości daty i godziny, gdy są one przechowywane w SQL Server. Możemy użyć DBCC PAGE() aby sprawdzić rzeczywistą stronę w pliku danych.

Ale najpierw musimy wstawić dane do naszych kolumn.

Wstaw dane:

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

Wybierz dane (tylko po to, aby je sprawdzić):

SELECT * FROM Datetime2vsDatetime;

Wynik:

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

Korzystanie z DBCC PAGE()

Tutaj używamy DBCC PAGE() aby sprawdzić rzeczywistą stronę w pliku danych.

Najpierw użyjemy DBCC IND() aby znaleźć PagePID:

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

Wynik (przy użyciu wyjścia pionowego):

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

Zwraca to dwa rekordy. Interesuje nas PageType 1 (drugi rekord). Chcemy mieć PagePID z tego rekordu. W tym przypadku PagePID to 320 .

Teraz możemy wziąć ten PagePID i użyć go w następujący sposób:

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

Daje to dużo danych, ale interesuje nas głównie następująca część:

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                                    

To pokazuje, że data i godzina używa długości 8 bajtów i datetime2(3) używa 7 bajtów, gdy jest przechowywany w bazie danych.

To wzmacnia argumentację za użyciem datetime2 ponad data i godzina podczas projektowania nowych baz danych, zwłaszcza jeśli problemem jest rozmiar pamięci.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Metoda SqlDataAdapter.Fill wolno

  2. Dynamiczne kolumny przestawne w SQL Server

  3. Przewodnik po CTE w SQL Server

  4. Obrót wielu kolumn w T-SQL

  5. SQL Server:czy powinienem używać tabel information_schema zamiast tabel sys?