Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

datetime срещу datetime2 в SQL Server:Каква е разликата?

Тази статия изследва основните разлики между дата и час и дата и час2 типове данни в SQL Server.

Ако не сте сигурни кой да използвате, използвайте datetime2 (вижте предимствата му по-долу).

Ето таблица, която очертава основните разлики между тези два типа.

Функция дата и час datetime2
Съвместим с SQL (ANSI и ISO 8601) Не Да
Период от време 1753-01-01 до 9999-12-31 0001-01-01 до 9999-12-31
Диапазон от време 00:00:00 до 23:59:59,997 00:00:00 до 23:59:59,9999999
Дължина на знака 19 позиции минимум
23 максимум
19 позиции минимум
27 максимум
Размер на съхранение 8 байта 6 до 8 байта, в зависимост от прецизността*

* Плюс 1 байт за съхраняване на точността

Точност Закръглено до стъпки от .000, .003 или .007 секунди 100 наносекунди
Дефинирана от потребителя точност на дробна секунда Не Да
Изместване на часовата зона Няма Няма
Осведомяване и запазване на изместването на часовата зона Не Не
Наясно с лятното часово време Не Не

Предимства на ‘datetime2’

Както се вижда в таблицата по-горе, datetime2 type има много предимства пред datetime , включително:

  • по-голям период от време
  • по-голяма дробна точност по подразбиране
  • по избор, определена от потребителя точност
  • по-висока точност, дори когато се използва същия брой десетични знаци като дата и час (т.е. 3)
  • по-малък размер на хранилището при използване на същия брой десетични знаци като дата и час , но с по-висока точност*
  • опцията за използване с 2 байта по-малко място за съхранение от datetime (макар и с по-ниска точност)*
  • в съответствие със стандартите SQL (ANSI и ISO 8601)

* В някои случаи datetime2 стойност използва допълнителен байт за съхраняване на точността, което би довело до същия размер на съхранение като datetime при използване на същия брой десетични знаци. Прочетете, за да научите повече за това.

Трябва ли да използвам „datetime“ или „datetime2“?

Microsoft препоръчва datetime2 над дата и час за нова работа (и по същите причини, изброени по-горе).

Следователно, трябва да използвате datetime2 , освен ако нямате конкретна причина да не го правите (като например работа с наследена система).

Пример 1 – Основно сравнение

Ето един бърз пример, за да демонстрирате основната разлика между дата и час и дата и час2 .

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

Резултат:

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

Тук задавам дата и час променлива на същата стойност като datetime2 променлива. Това води до преобразуване на стойността в datetime и след това можем да използваме SELECT изявление, за да видите резултата.

В този случай datetime2 променливата използва скала от 7, което означава 7 знака след десетичната запетая. Дата и час стойността, от друга страна, използва само 3 знака след десетичната запетая, а последната й дробна цифра се закръглява нагоре (тъй като този тип данни закръгля дробните секунди до стъпки от .000, .003 или .007 секунди).

Пример 2 – Използване на 3 десетични знака

Ако намаля datetime2 мащабиране до 3 (за да съответства на dateime ), ето какво се случва.

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

Резултат:

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

И така, datetime2 стойността също се закръглява в този случай. Той обаче се закръгля само до 556 – не скача до 557 като дата и час стойността.

Разбира се, единствената причина е datetime2 стойността се закръглява нагоре, защото следната цифра е 5 или по-висока. Ако намалим следната цифра, не се извършва закръгляне:

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

Резултат:

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

Въпреки това, datetime стойността продължава да се закръглява нагоре.

Пример 3 – Задаване на стойности от низови литерали

В предишните примери dateime стойността беше присвоена чрез задаване на същата стойност като datetime2 стойност. Когато направим това, SQL Server извършва имплицитно преобразуване, за да могат данните да „прилягат“ на новия тип данни.

Въпреки това, ако се опитаме да присвоим същия низов литерал на datetime променлива, която присвоихме на datetime2 , получаваме грешка:

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

Резултат:

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

Това е така, защото дата и час приема само низови литерали, които имат 3 или по-малко дробни секунди.

Така че, за да преодолеем този проблем, трябва да намалим дробната част до само 3 (или по-малко) знака след десетичната запетая.

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

Резултат:

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

datetime2 типът няма това ограничение, дори когато се използва скала от 3.

Пример 4 – Размер за съхранение

Дата и час типът данни има фиксиран размер на съхранение от 8 байта.

datetime2 от друга страна, може да бъде 6, 7 или 8 байта, в зависимост от неговата точност.

Когато използвате 3 знака след десетичната запетая, datetime2 използва само 7 байта, което означава, че използва по-малко място за съхранение от datetime (с по-голяма точност).

Въпреки това Microsoft заявява, че datetime2 type също използва 1 допълнителен байт, за да запази своята точност. Така че в този случай ще използва 8 байта. Следователно можем да преразгледаме предишното изявление, като кажем, че използва 7, 8 или 9 байта.

Това обаче вероятно зависи от това дали го съхраняваме в таблица или в променлива и дали го преобразуваме в двоична константа или не.

Ето какво се случва, ако използваме DATALENGTH() функция за връщане на броя байтове, използвани за всяка от нашите стойности:

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

Резултат

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

Но ако ги преобразуваме в varbinary , получаваме следното:

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

Резултат

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

И така, datetime2 използва допълнителен байт, когато се преобразува в varbinary , като по този начин го привеждате до същия размер за съхранение като datetime .

Следният пример обаче показва, че когато данните се съхраняват в колона на база данни, получаваме дължина от 7 байта за datetime2 и 8 байта за дата и час .

При съхраняване на datetime2 стойности в база данни, дефиницията на колоната включва точността. В този случай стойностите във всеки ред не се нуждаят от допълнителен байт за съхраняване на точността и можем да кажем, че datetime2 използва по-малко място за съхранение от datetime при използване на същия брой дробни секунди.

Пример 5 – Размер на съхранение за съхранени данни

В този пример създавам база данни и използвам COL_LENGTH за да върне дължината на всяка колона в байтове. След това вмъквам datetime2 и дата и час стойност в него и използвайте DBCC PAGE() за да намерите дължината на действителните данни във файла на страницата. Това ни показва пространството за съхранение, което всеки тип данни използва, когато се съхранява в база данни.

Създайте база данни:

CREATE DATABASE CompareTypes;

Създайте таблица:

USE CompareTypes;

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

В този случай създавам две колони – едната е datetime колона, а другата е datetime2 колона.

Проверете дължината на колоната

Проверете дължината (в байтове) на всяка колона:

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

Резултат:

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

И така, виждаме, че datetime2 колоната има дължина от 7 байта в сравнение с datetime с дължина от 8 байта.

Вмъкване на данни

Сега нека разгледаме размера на съхранение на действителните стойности за дата и час, когато те се съхраняват в SQL Server. Можем да използваме DBCC PAGE() за да проверите действителната страница във файла с данни.

Но първо трябва да вмъкнем данни в нашите колони.

Вмъкване на данни:

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

Изберете данните (само за да ги проверите):

SELECT * FROM Datetime2vsDatetime;

Резултат:

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

Използване на DBCC PAGE()

Ето къде използваме DBCC PAGE() за да проверите действителната страница във файла с данни.

Първо, ще използваме DBCC IND() за да намерите PagePID:

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

Резултат (с помощта на вертикален изход):

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

Това връща два записа. Интересуваме се от PageType от 1 (2-ри запис). Искаме PagePID от този запис. В този случай PagePID е 320 .

Сега можем да вземем този PagePID и да го използваме в следното:

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

Това произвежда много данни, но ние се интересуваме основно от следната част:

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                                    

Това показва, че дата и час използва дължина от 8 байта и datetime2(3) използва 7 байта, когато се съхранява в база данни.

Така че това подсилва доводите за използване на datetime2 над дата и час когато проектирате нови бази данни, особено ако размерът на хранилището е проблем.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как правилно да вмъкнете нов ред в nvarchar

  2. SQL Server:Как да получите справка за външен ключ от information_schema?

  3. Поправете „датата е несъвместима с int“ в SQL Server при добавяне към или изваждане от дата

  4. SQL Server 2008 не може да влезе с новосъздадения потребител

  5. 3 начина за конвертиране на HEX в INT в SQL Server (T-SQL)