Bài viết này khám phá những điểm khác biệt chính giữa datetime2 và smalldatetime kiểu dữ liệu trong SQL Server.
Cả hai kiểu dữ liệu đều được sử dụng để lưu trữ các giá trị ngày và giờ, tuy nhiên, có một số khác biệt quan trọng giữa hai kiểu. Trong hầu hết các trường hợp, bạn nên sử dụng datetime2 (Microsoft cũng khuyến nghị điều này), tuy nhiên có thể có một số trường hợp bạn cần sử dụng smalldatetime .
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 | smalldatetime | datetime2 |
---|---|---|
Tuân thủ SQL (ANSI &ISO 8601) | Không | Có |
Phạm vi ngày | 1900-01-01 đến 2079-06-06 | 0001-01-01 đến 9999-12-31 |
Phạm vi thời gian | 00:00:00 đến 23:59:59 | 00:00:00 đến 23:59:59.9999999 |
Độ dài ký tự | tối đa 19 vị trí | tối thiểu 19 vị trí tối đa 27 vị trí |
Kích thước lưu trữ | 4 byte, cố định | 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 | Một phút | 100 nano giây |
Độ chính xác phân số giây | Không | Có |
Độ 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 smalldatetime , bao gồm:
- phạm vi ngày lớn hơn
- độ chính xác phân số giây
- độ chính xác tùy chọn do người dùng chỉ định
- độ chính xác cao 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 phụ để lưu trữ độ chính xác, tuy nhiên khi được lưu trữ trong cơ sở dữ liệu, độ chính xác được bao gồm trong định nghĩa cột, vì vậy giá trị được lưu trữ thực tế không yêu cầu byte bổ sung.
Tôi nên sử dụng "datetime" hay "smalldatetime"?
Microsoft khuyến nghị datetime2 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 datetime2 và 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';
Kết quả:
+-----------------------------+---------------------+ | datetime2 | smalldatetime | |-----------------------------+---------------------| | 2025-05-21 10:15:30.5555555 | 2025-05-21 10:16:00 | +-----------------------------+---------------------+
Ở đây, tôi đã đặt smalldatetime 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 smalldatetime và sau đó chúng ta có thể sử dụng SELECT
để xem giá trị của mỗi biến.
Trong trường hợp này, datetime2 biến sử dụng thang điểm 7, có nghĩa là nó có 7 chữ số thập phân. smalldatetime mặt khác, không có bất kỳ vị trí thập phân. Hơn nữa, giây của nó được đặt thành 0 và phút của nó được làm tròn.
Điều này được mong đợi, vì tài liệu chính thức của Microsoft nói rằng smalldatetime
Thời gian của ‘s là dựa trên một ngày 24 giờ, với giây luôn là 0 (:00) và không có giây phân số
.
Vì vậy, chúng ta có thể thấy rằng datetime2 loại cung cấp giá trị ngày / giờ chính xác và chính xác hơn nhiều.
Tất nhiên, bạn có thể không cần tất cả những giây phân số đó. Một trong những điều tốt về datetime2 là bạn có thể chỉ định số giây phân số (nếu có) bạn muốn.
Ví dụ 2 - Sử dụng Vị trí Thập phân Ít hơn
Trong ví dụ này, tôi giảm datetime2 tỷ lệ thành 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';
Kết quả:
+---------------------+---------------------+ | datetime2 | smalldatetime | |---------------------+---------------------| | 2025-05-21 10:15:31 | 2025-05-21 10:16:00 | +---------------------+---------------------+
Trong trường hợp này, datetime2 giá trị không còn bao gồm một phần phân số. Cả hai loại hiện có cùng độ dài ký tự (19 vị trí).
Nhưng vẫn có sự khác biệt.
datetime2 giá trị tôn vinh giá trị giây, mặc dù trong trường hợp này, số giây của nó đã được làm tròn. Như đã đề cập, smalldatetime thành phần giây của giá trị luôn được đặt thành 0 và trong trường hợp này, số phút của nó đã được làm tròn.
Lý do datetime2 thành phần giây được làm tròn lên là do phần phân số là 5 hoặc cao hơn. Nếu chúng ta giảm phần phân số, không có phép làm tròn nào được thực hiện:
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';
Kết quả:
+---------------------+---------------------+ | datetime2 | smalldatetime | |---------------------+---------------------| | 2025-05-21 10:15:30 | 2025-05-21 10:16:00 | +---------------------+---------------------+
Tuy nhiên, smalldatetime số phút của 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, smalldateime 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 smalldatetime , chúng tôi gặp lỗi:
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';
Kết quả:
Msg 295, Level 16, State 3, Line 5 Conversion failed when converting character string to smalldatetime data type.
Đó là vì smalldatetime chỉ chấp nhận các ký tự chuỗi có từ 3 giây phân số trở xuống.
Bạn có thể mong đợi rằng nó sẽ không chấp nhận các ký tự chuỗi với bất kỳ giây phân số, vì nó không bao gồm giây phân số, nhưng không phải vậy. Nó vui vẻ chấp nhận 3 giây phân số, nhưng không còn nữa.
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(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';
Kết quả:
+---------------------+---------------------+ | datetime2 | smalldatetime | |---------------------+---------------------| | 2025-05-21 10:15:30 | 2025-05-21 10:16:00 | +---------------------+---------------------+
datetime2 loại không có giới hạn này, ngay cả khi sử dụng thang điểm 0.
Ví dụ 4 - Kích thước bộ nhớ
smalldatetime kiểu dữ liệu có kích thước lưu trữ cố định là 4 byte. Đây là một trong số ít lợi ích của smalldatetime đã hơn datetime2 .
datetime2 có thể là 6, 7 hoặc 8 byte, tùy thuộc vào độ chính xác của nó. Vì vậy, một datetime2 giá trị sẽ luôn sử dụng nhiều hơn ít nhất 2 byte bộ nhớ so với smalldatetime giá trị.
Microsoft tuyên bố rằng datetime2 type cũng sử dụng thêm 1 byte để lưu trữ độ chính xác của nó. Trong trường hợp đó, type sẽ sử dụng ít hơn 3 byte so với smalldatetime .
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(0), @thesmalldatetime smalldatetime; SET @thedatetime2 = '2025-05-21 10:15:30'; SET @thesmalldatetime = @thedatetime2; SELECT DATALENGTH(@thedatetime2) AS 'datetime2', DATALENGTH(@thesmalldatetime) AS 'smalldatetime';
Kết quả
+-------------+-----------------+ | datetime2 | smalldatetime | |-------------+-----------------| | 6 | 4 | +-------------+-----------------+
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(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';
Kết quả
+-------------+-----------------+ | datetime2 | smalldatetime | |-------------+-----------------| | 7 | 4 | +-------------+-----------------+
Vì vậy, datetime2 sử dụng thêm một byte khi được chuyển đổi thành varbinary . Nhiều nhà phát triển giả định rằng chuyển đổi thành varbinary đại diện cho cách SQL Server thực sự lưu trữ các giá trị ngày và giờ.
Tuy nhiên, điều này chỉ đúng một phần. Mặc dù đúng là SQL Server lưu trữ các giá trị ngày và giờ của nó ở dạng thập lục phân, nhưng giá trị hex đó không thực sự bao gồm độ chính xác. Điều này là do độ chính xác được bao gồm trong định nghĩa cột. Nhưng khi chúng tôi chuyển đổi thành varbinary như chúng ta đã làm trong ví dụ trước, độ chính xác được thêm vào trước và điều này thêm một byte bổ sung.
Ví dụ sau đây chứng minh điều này. Nó 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 6 byte cho datetime2 so với 4 byte cho smalldatetime .
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à smalldatetime 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 Datetime2vsSmalldatetime ( TheDateTime2 datetime2(0), TheSmallDateTime smalldatetime );
Trong trường hợp này, tôi tạo hai cột - một cột là datetime2 (0) và cột kia là smalldatetime 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.Datetime2vsSmalldatetime' , 'TheDateTime2' ) AS 'datetime2', COL_LENGTH ( 'dbo.Datetime2vsSmalldatetime' , 'TheSmallDateTime' ) AS 'smalldatetime';
Kết quả:
+-------------+-----------------+ | datetime2 | smalldatetime | |-------------+-----------------| | 6 | 4 | +-------------+-----------------+
Vì vậy, chúng tôi thấy rằng datetime2 (0) cột có độ dài 6 byte, so với smalldatetime Độ dài của ‘s là 4 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'; INSERT INTO Datetime2vsSmalldatetime ( TheSmallDateTime, TheDateTime2 ) SELECT @thedatetime2, @thedatetime2;
Chọn dữ liệu (chỉ để kiểm tra):
SELECT * FROM Datetime2vsSmalldatetime;
Kết quả:
+---------------------+---------------------+ | TheDateTime2 | TheSmallDateTime | |---------------------+---------------------| | 2025-05-21 10:15:30 | 2025-05-21 10:16:00 | +---------------------+---------------------+
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.Datetime2vsSmalldatetime', 0);
Kết quả (sử dụng đầu ra dọc):
-[ 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
Đ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à 344 .
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, 344, 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 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
Điều này cho thấy rằng smalldatetime có độ dài 4 byte và datetime2 (0) có 6 byte khi được lưu trữ trong cơ sở dữ liệu.
Vì vậy, trong trường hợp này, chỉ có chênh lệch 2 byte, nhưng datetime2 (0) chính xác hơn và tuân theo các tiêu chuẩn ANSI và ISO 8601.