Bài viết này khám phá những điểm khác biệt chính giữa ngày giờ và datetime2 kiểu dữ liệu trong SQL Server.
Nếu bạn không chắc nên sử dụng cái nào, hãy sử dụng datetime2 (xem ưu điểm của nó bên dưới).
Dưới đây là bảng phác thảo sự khác biệt chính giữa hai loại này.
Tính năng | ngày giờ | datetime2 |
---|---|---|
Tuân thủ SQL (ANSI &ISO 8601) | Không | Có |
Phạm vi ngày | 1753-01-01 đến 9999-12-31 | 0001-01-01 đến 9999-12-31 |
Phạm vi thời gian | 00:00:00 đến 23:59:59.997 | 00:00:00 đến 23:59:59.9999999 |
Độ dài ký tự | tối thiểu 19 vị trí tối đa 23 vị trí | tối thiểu 19 vị trí tối đa 27 vị trí |
Kích thước bộ nhớ | 8 byte | 6 đến 8 byte, tùy thuộc vào độ chính xác * * Thêm 1 byte để lưu trữ độ chính xác |
Độ chính xác | Được làm tròn đến gia số .000, .003 hoặc .007 giây | 100 nano giây |
Độ chính xác phân số giây do người dùng xác định | Không | Có |
Chênh lệch múi giờ | Không có | Không có |
Nhận biết và bảo toàn độ lệch múi giờ | Không | Không |
Nhận biết tiết kiệm ánh sáng ban ngày | Không | Không |
Ưu điểm của 'datetime2'
Như đã thấy trong bảng trên, datetime2 loại có nhiều ưu điểm hơn datetime , bao gồm:
- phạm vi ngày lớn hơn
- độ chính xác phân số mặc định lớn hơn
- độ chính xác tùy chọn do người dùng chỉ định
- độ chính xác cao hơn, ngay cả khi sử dụng cùng một số vị trí thập phân như ngày giờ (tức là 3)
- kích thước bộ nhớ nhỏ hơn khi sử dụng sử dụng cùng một số vị trí thập phân như ngày giờ , nhưng với độ chính xác cao hơn *
- tùy chọn sử dụng bộ nhớ ít hơn 2 byte so với datetime (mặc dù độ chính xác thấp hơn) *
- phù hợp với các tiêu chuẩn SQL (ANSI &ISO 8601)
* Trong một số trường hợp, datetime2 giá trị sử dụng một byte bổ sung để lưu trữ độ chính xác, điều này sẽ dẫn đến cùng kích thước lưu trữ với datetime khi sử dụng cùng một số chữ số thập phân. Đọc để tìm hiểu thêm về điều này.
Tôi nên sử dụng "datetime" hay "datetime2"?
Microsoft khuyến nghị datetime2 qua ngày giờ cho công việc mới (và vì những lý do tương tự được liệt kê ở trên).
Do đó, bạn nên sử dụng datetime2 , trừ khi bạn có lý do cụ thể để không (chẳng hạn như làm việc với hệ thống cũ).
Ví dụ 1 - So sánh Cơ bản
Dưới đây là một ví dụ nhanh để chứng minh sự khác biệt cơ bản giữa ngày giờ và 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';
Kết quả:
+-----------------------------+-------------------------+ | datetime2 | datetime | |-----------------------------+-------------------------| | 2025-05-21 10:15:30.5555555 | 2025-05-21 10:15:30.557 | +-----------------------------+-------------------------+
Ở đây, tôi đã đặt ngày giờ biến thành cùng một giá trị với datetime2 Biến đổi. Điều này khiến giá trị được chuyển đổi thành datetime và sau đó chúng ta có thể sử dụng SELECT
để xem kết quả.
Trong trường hợp này, datetime2 biến sử dụng thang điểm 7, có nghĩa là 7 chữ số thập phân. Ngày giờ mặt khác, giá trị chỉ sử dụng 3 chữ số thập phân và chữ số thập phân cuối cùng của nó được làm tròn (vì kiểu dữ liệu này làm tròn số giây phân số thành giá trị .000, .003 hoặc .007 giây).
Ví dụ 2 - Sử dụng 3 vị trí thập phân
Nếu tôi giảm datetime2 chia tỷ lệ thành 3 (để khớp với ngày giờ ), đây là những gì sẽ xảy ra.
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';
Kết quả:
+-------------------------+-------------------------+ | datetime2 | datetime | |-------------------------+-------------------------| | 2025-05-21 10:15:30.556 | 2025-05-21 10:15:30.557 | +-------------------------+-------------------------+
Vì vậy, datetime2 giá trị cũng được làm tròn trong trường hợp này. Tuy nhiên, nó chỉ được làm tròn thành 556 - nó không nhảy đến 557 như ngày giờ giá trị không.
Tất nhiên, lý do duy nhất khiến datetime2 giá trị được làm tròn lên là do chữ số sau là 5 hoặc cao hơn. Nếu chúng ta giảm chữ số sau, không có phép làm tròn nào được thực hiện:
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';
Kết quả:
+-------------------------+-------------------------+ | datetime2 | datetime | |-------------------------+-------------------------| | 2025-05-21 10:15:30.555 | 2025-05-21 10:15:30.557 | +-------------------------+-------------------------+
Tuy nhiên, ngày giờ giá trị tiếp tục được làm tròn.
Ví dụ 3 - Đặt giá trị từ chữ viết chuỗi
Trong các ví dụ trước, ngày giờ giá trị đã được chỉ định bằng cách đặt nó thành giá trị giống như datetime2 giá trị. Khi chúng tôi làm điều đó, SQL Server thực hiện một chuyển đổi ngầm định để dữ liệu “khớp” với kiểu dữ liệu mới.
Tuy nhiên, nếu chúng tôi cố gắng gán cùng một chuỗi ký tự cho datetime biến mà chúng tôi đã chỉ định cho datetime2 , chúng tôi gặp lỗi:
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';
Kết quả:
Msg 241, Level 16, State 1, Line 5 Conversion failed when converting date and/or time from character string.
Điều này là do ngày giờ chỉ chấp nhận các ký tự chuỗi có 3 giây phân số trở xuống.
Vì vậy, để khắc phục vấn đề này, chúng ta cần giảm phần phân số xuống chỉ còn 3 (hoặc ít hơn) chữ số thập phân.
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';
Kết quả:
+-------------------------+-------------------------+ | datetime2 | datetime | |-------------------------+-------------------------| | 2025-05-21 10:15:30.555 | 2025-05-21 10:15:30.557 | +-------------------------+-------------------------+
datetime2 loại không có giới hạn này, ngay cả khi sử dụng thang điểm 3.
Ví dụ 4 - Kích thước bộ nhớ
Ngày giờ kiểu dữ liệu có kích thước lưu trữ cố định là 8 byte.
datetime2 mặt khác, có thể là 6, 7 hoặc 8 byte, tùy thuộc vào độ chính xác của nó.
Khi sử dụng 3 chữ số thập phân, datetime2 chỉ sử dụng 7 byte, có nghĩa là nó sử dụng ít dung lượng lưu trữ hơn datetime (với độ chính xác cao hơn).
Tuy nhiên, Microsoft tuyên bố rằng datetime2 kiểu cũng sử dụng thêm 1 byte để lưu trữ độ chính xác của nó. Vì vậy, trong trường hợp này, nó sẽ sử dụng 8 byte. Và do đó, chúng tôi có thể sửa đổi câu lệnh trước đó bằng cách nói rằng nó sử dụng 7, 8 hoặc 9 byte.
Tuy nhiên, điều này có thể phụ thuộc vào việc chúng ta đang lưu trữ nó trong bảng hay trong một biến và liệu chúng ta có đang chuyển nó thành hằng số nhị phân hay không.
Đây là điều sẽ xảy ra nếu chúng tôi sử dụng DATALENGTH()
hàm để trả về số byte được sử dụng cho mỗi giá trị của chúng ta:
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';
Kết quả
+-------------+------------+ | datetime2 | datetime | |-------------+------------| | 7 | 8 | +-------------+------------+
Nhưng nếu chúng tôi chuyển đổi chúng thành varbinary , chúng tôi nhận được những điều sau:
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';
Kết quả
+-------------+------------+ | datetime2 | datetime | |-------------+------------| | 8 | 8 | +-------------+------------+
Vì vậy, datetime2 sử dụng thêm một byte khi được chuyển đổi thành varbinary , do đó đưa nó về cùng kích thước bộ nhớ với datetime .
Tuy nhiên, ví dụ sau cho thấy rằng khi dữ liệu được lưu trữ trong cột cơ sở dữ liệu, chúng tôi nhận được độ dài 7 byte cho datetime2 và 8 byte cho datetime .
Khi lưu trữ datetime2 giá trị trong cơ sở dữ liệu, định nghĩa cột bao gồm độ chính xác. Trong trường hợp này, các giá trị trong mỗi hàng không cần thêm byte để lưu trữ độ chính xác và chúng ta có thể nói rằng datetime2 sử dụng ít dung lượng bộ nhớ hơn datetime khi sử dụng cùng một số giây phân số.
Ví dụ 5 - Kích thước bộ nhớ cho dữ liệu được lưu trữ
Trong ví dụ này, tôi tạo cơ sở dữ liệu và sử dụng COL_LENGTH
để trả về độ dài của mỗi cột, tính bằng byte. Sau đó, tôi chèn một datetime2 và ngày giờ giá trị vào nó và sử dụng DBCC PAGE()
để tìm độ dài của dữ liệu thực trong tệp trang. Điều này cho chúng ta thấy không gian lưu trữ mà mỗi loại dữ liệu sử dụng khi được lưu trữ trong cơ sở dữ liệu.
Tạo cơ sở dữ liệu:
CREATE DATABASE CompareTypes;
Tạo bảng:
USE CompareTypes; CREATE TABLE Datetime2vsDatetime ( TheDateTime datetime, TheDateTime2 datetime2(3) );
Trong trường hợp này, tôi tạo hai cột - một cột là ngày giờ và cột kia là datetime2 cột.
Kiểm tra độ dài cột
Kiểm tra độ dài (tính bằng byte) của mỗi cột:
SELECT COL_LENGTH ( 'dbo.Datetime2vsDatetime' , 'TheDateTime2' ) AS 'datetime2', COL_LENGTH ( 'dbo.Datetime2vsDatetime' , 'TheDateTime' ) AS 'datetime';
Kết quả:
+-------------+------------+ | datetime2 | datetime | |-------------+------------| | 7 | 8 | +-------------+------------+
Vì vậy, chúng tôi thấy rằng datetime2 cột có độ dài 7 byte so với datetime Độ dài của ‘s là 8 byte.
Chèn dữ liệu
Bây giờ, hãy xem kích thước lưu trữ của các giá trị ngày và giờ thực tế khi chúng được lưu trữ trong SQL Server. Chúng ta có thể sử dụng DBCC PAGE()
để kiểm tra trang thực tế trong tệp dữ liệu.
Nhưng trước tiên, chúng ta cần chèn dữ liệu vào các cột của mình.
Chèn dữ liệu:
DECLARE @thedatetime2 datetime2 = '2025-05-21 10:15:30.5554444'; INSERT INTO Datetime2vsDatetime ( TheDateTime, TheDateTime2 ) SELECT @thedatetime2, @thedatetime2;
Chọn dữ liệu (chỉ để kiểm tra):
SELECT * FROM Datetime2vsDatetime;
Kết quả:
+-------------------------+-------------------------+ | TheDateTime | TheDateTime2 | |-------------------------+-------------------------| | 2025-05-21 10:15:30.557 | 2025-05-21 10:15:30.555 | +-------------------------+-------------------------+
Sử dụng DBCC PAGE ()
Đây là nơi chúng tôi sử dụng DBCC PAGE()
để kiểm tra trang thực tế trong tệp dữ liệu.
Đầu tiên, chúng tôi sẽ sử dụng DBCC IND()
để tìm PagePID:
DBCC IND('CompareTypes', 'dbo.Datetime2vsDatetime', 0);
Kết quả (sử dụng đầu ra dọc):
-[ 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
Điều này trả về hai bản ghi. Chúng tôi quan tâm đến Loại trang 1 (bản ghi thứ 2). Chúng tôi muốn có PagePID từ bản ghi đó. Trong trường hợp này, PagePID là 320 .
Bây giờ chúng ta có thể lấy PagePID đó và sử dụng nó như sau:
DBCC TRACEON(3604, -1); DBCC PAGE(CompareTypes, 1, 320, 3);
Điều này tạo ra rất nhiều dữ liệu, nhưng chúng tôi chủ yếu quan tâm đến phần sau:
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
Điều này cho thấy rằng ngày giờ sử dụng độ dài 8 byte và datetime2 (3) sử dụng 7 byte khi được lưu trữ trong cơ sở dữ liệu.
Vì vậy, điều này củng cố trường hợp sử dụng datetime2 qua ngày giờ khi thiết kế cơ sở dữ liệu mới, đặc biệt nếu kích thước lưu trữ là mối quan tâm.