Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

datetime2 vs smalldatetime di SQL Server:Apa Bedanya?

Artikel ini membahas perbedaan utama antara datetime2 dan waktu kecil tipe data di SQL Server.

Kedua tipe data tersebut digunakan untuk menyimpan nilai tanggal dan waktu, namun ada beberapa perbedaan penting di antara keduanya. Dalam kebanyakan kasus, Anda lebih baik menggunakan datetime2 (Microsoft juga merekomendasikan ini), namun mungkin ada beberapa skenario di mana Anda perlu menggunakan smalldatetime .

Berikut tabel yang menjelaskan perbedaan utama antara kedua jenis ini.

Fitur waktu kecil datetime2
Sesuai dengan SQL (ANSI &ISO 8601) Tidak Ya
Rentang Tanggal 1900-01-01 hingga 2079-06-06 0001-01-01 hingga 9999-12-31
Rentang Waktu 00:00:00 sampai 23:59:59 00:00:00 sampai 23:59:59.9999999
Panjang Karakter Maksimum 19 posisi Minimum 19 posisi
maksimum 27
Ukuran Penyimpanan 4 byte, diperbaiki 6 hingga 8 byte, tergantung pada presisi*

* Ditambah 1 byte untuk menyimpan presisi

Akurasi Satu menit 100 nanodetik
Presisi kedua pecahan Tidak Ya
Presisi pecahan detik yang ditentukan pengguna Tidak Ya
Offset Zona Waktu Tidak ada Tidak ada
Awas dan pelestarian zona waktu Tidak Tidak
Mengingat musim panas Tidak Tidak

Keuntungan dari 'datetime2'

Seperti yang terlihat pada tabel di atas, datetime2 type memiliki banyak keunggulan dibandingkan smalldatetime , termasuk:

  • rentang tanggal yang lebih besar
  • presisi detik pecahan
  • presisi yang ditentukan pengguna opsional
  • akurasi lebih tinggi
  • sejajar dengan standar SQL (ANSI &ISO 8601)

* Dalam beberapa kasus datetime2 value menggunakan byte ekstra untuk menyimpan presisi, namun saat disimpan dalam database, presisi disertakan dalam definisi kolom, sehingga nilai tersimpan yang sebenarnya tidak memerlukan byte tambahan.

Haruskah saya menggunakan 'datetime' atau 'smalldatetime'?

Microsoft merekomendasikan datetime2 untuk pekerjaan baru (dan untuk alasan yang sama seperti yang disebutkan di atas).

Oleh karena itu, Anda harus menggunakan datetime2 , kecuali Anda memiliki alasan khusus untuk tidak melakukannya (seperti bekerja dengan sistem lama).

Contoh 1 – Perbandingan Dasar

Berikut adalah contoh cepat untuk menunjukkan perbedaan mendasar antara datetime2 dan waktu kecil .

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

Hasil:

+-----------------------------+---------------------+
| datetime2                   | smalldatetime       |
|-----------------------------+---------------------|
| 2025-05-21 10:15:30.5555555 | 2025-05-21 10:16:00 |
+-----------------------------+---------------------+

Di sini, saya menyetel smalldatetime variabel dengan nilai yang sama dengan datetime2 variabel. Ini menyebabkan nilai dikonversi ke smalldatetime dan kemudian kita dapat menggunakan SELECT pernyataan untuk melihat nilai setiap variabel.

Dalam hal ini, datetime2 variabel menggunakan skala 7, yang berarti memiliki 7 tempat desimal. waktu kecil nilai di sisi lain, tidak memiliki apa pun tempat desimal. Selanjutnya, detiknya disetel ke nol, dan menitnya dibulatkan.

Hal ini diharapkan, karena dokumentasi resmi Microsoft menyatakan bahwa smalldatetime waktu berdasarkan 24 jam sehari, dengan detik selalu nol (:00) dan tanpa pecahan detik .

Jadi kita dapat melihat bahwa datetime2 type memberikan nilai tanggal/waktu yang jauh lebih tepat dan akurat.

Tentu saja, Anda mungkin tidak membutuhkan semua detik pecahan itu. Salah satu hal baik tentang datetime2 adalah Anda dapat menentukan berapa banyak (jika ada) detik pecahan yang Anda inginkan.

Contoh 2 – Menggunakan Lebih Sedikit Tempat Desimal

Dalam contoh ini saya mengurangi datetime2 skala ke 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';

Hasil:

+---------------------+---------------------+
| datetime2           | smalldatetime       |
|---------------------+---------------------|
| 2025-05-21 10:15:31 | 2025-05-21 10:16:00 |
+---------------------+---------------------+

Dalam hal ini, datetime2 nilai tidak lagi termasuk bagian pecahan. Kedua tipe sekarang memiliki panjang karakter yang sama (19 posisi).

Tapi tetap ada perbedaan.

datetime2 value menghormati nilai detik, meskipun dalam hal ini detiknya telah dibulatkan. Seperti yang disebutkan, waktu kecil komponen nilai detik selalu disetel ke nol, dan dalam hal ini, menitnya telah dibulatkan.

Alasan datetime2 komponen detik dibulatkan ke atas karena bagian pecahannya adalah 5 atau lebih tinggi. Jika kita mengurangi bagian pecahan, tidak ada pembulatan yang dilakukan:

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

Hasil:

+---------------------+---------------------+
| datetime2           | smalldatetime       |
|---------------------+---------------------|
| 2025-05-21 10:15:30 | 2025-05-21 10:16:00 |
+---------------------+---------------------+

Namun, waktu kecil menit nilai terus dibulatkan.

Contoh 3 – Menetapkan Nilai dari Literal String

Pada contoh sebelumnya, waktu kecil nilai ditetapkan dengan menyetelnya ke nilai yang sama dengan datetime2 nilai. Ketika kami melakukannya, SQL Server melakukan konversi implisit agar data "sesuai" dengan tipe data baru.

Namun, jika kami mencoba menetapkan literal string yang sama ke smalldatetime variabel, kami mendapatkan kesalahan:

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

Hasil:

Msg 295, Level 16, State 3, Line 5
Conversion failed when converting character string to smalldatetime data type.

Itu karena waktu kecil hanya menerima literal string yang memiliki 3 atau kurang pecahan detik.

Anda mungkin berharap bahwa itu tidak akan menerima literal string dengan apa saja pecahan detik, mengingat itu tidak termasuk pecahan detik, tapi bukan itu masalahnya. Dengan senang hati menerima 3 detik pecahan, tetapi tidak lebih.

Jadi untuk mengatasi masalah ini, kita perlu mengurangi bagian pecahan menjadi hanya 3 (atau kurang) tempat desimal.

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

Hasil:

+---------------------+---------------------+
| datetime2           | smalldatetime       |
|---------------------+---------------------|
| 2025-05-21 10:15:30 | 2025-05-21 10:16:00 |
+---------------------+---------------------+

datetime2 type tidak memiliki batasan ini, bahkan saat menggunakan skala 0.

Contoh 4 – Ukuran Penyimpanan

waktu kecil tipe data memiliki ukuran penyimpanan tetap 4 byte. Ini adalah salah satu dari sedikit manfaat smalldatetime memiliki lebih dari datetime2 .

datetime2 dapat berupa 6, 7, atau 8 byte, tergantung pada presisinya. Jadi datetime2 value akan selalu menggunakan penyimpanan minimal 2 byte lebih banyak daripada smalldatetime nilai.

Microsoft menyatakan bahwa datetime2 type juga menggunakan 1 byte tambahan untuk menyimpan presisinya, dalam hal ini akan menggunakan setidaknya 3 byte lebih dari smalldatetime .

Namun, ini mungkin tergantung pada apakah kita menyimpannya dalam tabel atau variabel, dan apakah kita mengonversinya menjadi konstanta biner atau tidak.

Inilah yang terjadi jika kita menggunakan DATALENGTH() fungsi untuk mengembalikan jumlah byte yang digunakan untuk setiap nilai kita:

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

Hasil

+-------------+-----------------+
| datetime2   | smalldatetime   |
|-------------+-----------------|
| 6           | 4               |
+-------------+-----------------+

Tetapi jika kita mengonversinya menjadi varbinary , kita mendapatkan yang berikut:

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

Hasil

+-------------+-----------------+
| datetime2   | smalldatetime   |
|-------------+-----------------|
| 7           | 4               |
+-------------+-----------------+

Jadi datetime2 menggunakan byte ekstra saat dikonversi ke varbinary . Banyak pengembang berasumsi bahwa mengonversi ke varbinary mewakili bagaimana SQL Server benar-benar menyimpan nilai tanggal dan waktu.

Ini hanya sebagian benar sekalipun. Meskipun benar bahwa SQL Server menyimpan nilai tanggal dan waktunya dalam heksadesimal, nilai hex tersebut sebenarnya tidak menyertakan presisi. Ini karena presisi termasuk dalam definisi kolom. Tetapi ketika kita mengonversi ke varbinary seperti yang kita lakukan pada contoh sebelumnya, presisi ditambahkan, dan ini menambahkan byte tambahan.

Contoh berikut menunjukkan hal ini. Ini menunjukkan bahwa ketika data disimpan dalam kolom database, kami mendapatkan panjang 6 byte untuk datetime2 vs 4 byte untuk smalldatetime .

Contoh 5 – Ukuran Penyimpanan untuk Data Tersimpan

Dalam contoh ini, saya membuat database dan menggunakan COL_LENGTH untuk mengembalikan panjang setiap kolom, dalam byte. Saya kemudian memasukkan datetime2 dan waktu kecil nilai ke dalamnya dan gunakan DBCC PAGE() untuk menemukan panjang data aktual dalam file halaman. Ini menunjukkan kepada kita ruang penyimpanan yang digunakan setiap tipe data saat disimpan dalam database.

Buat basis data:

CREATE DATABASE CompareTypes;

Buat tabel:

USE CompareTypes;

CREATE TABLE Datetime2vsSmalldatetime (
    TheDateTime2 datetime2(0),
    TheSmallDateTime smalldatetime
    );

Dalam hal ini saya membuat dua kolom – satu adalah datetime2(0) kolom dan yang lainnya adalah waktu kecil kolom.

Periksa Panjang Kolom

Periksa panjang (dalam byte) setiap kolom:

SELECT 
  COL_LENGTH ( 'dbo.Datetime2vsSmalldatetime' , 'TheDateTime2' ) AS 'datetime2',
  COL_LENGTH ( 'dbo.Datetime2vsSmalldatetime' , 'TheSmallDateTime' ) AS 'smalldatetime';  

Hasil:

+-------------+-----------------+
| datetime2   | smalldatetime   |
|-------------+-----------------|
| 6           | 4               |
+-------------+-----------------+

Jadi kita melihat bahwa datetime2(0) kolom memiliki panjang 6 byte, dibandingkan dengan smalldatetime panjangnya 4 byte.

Sisipkan Data

Sekarang mari kita lihat ukuran penyimpanan dari nilai tanggal dan waktu aktual saat disimpan di SQL Server. Kita dapat menggunakan DBCC PAGE() untuk memeriksa halaman sebenarnya dalam file data.

Tapi pertama-tama, kita perlu memasukkan data ke dalam kolom kita.

Masukkan data:

DECLARE @thedatetime2 datetime2 = '2025-05-21 10:15:30';
INSERT INTO Datetime2vsSmalldatetime ( TheSmallDateTime, TheDateTime2 )
SELECT @thedatetime2, @thedatetime2;

Pilih data (hanya untuk memeriksanya):

SELECT * FROM Datetime2vsSmalldatetime;

Hasil:

+---------------------+---------------------+
| TheDateTime2        | TheSmallDateTime    |
|---------------------+---------------------|
| 2025-05-21 10:15:30 | 2025-05-21 10:16:00 |
+---------------------+---------------------+

Menggunakan DBCC PAGE()

Di sinilah kami menggunakan DBCC PAGE() untuk memeriksa halaman sebenarnya dalam file data.

Pertama, kita akan menggunakan DBCC IND() untuk menemukan PagePID:

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

Hasil (menggunakan keluaran vertikal):

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

Ini mengembalikan dua catatan. Kami tertarik dengan PageType dari 1 (catatan ke-2). Kami ingin PagePID dari catatan itu. Dalam hal ini PagePID adalah 344 .

Sekarang kita dapat mengambil PagePID itu dan menggunakannya sebagai berikut:

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

Ini menghasilkan banyak data, tetapi kami terutama tertarik pada bagian berikut:

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                                          

Ini menunjukkan bahwa waktu kecil memiliki panjang 4 byte dan datetime2(0) memiliki 6 byte saat disimpan dalam database.

Jadi dalam hal ini, hanya ada perbedaan 2 byte, tetapi datetime2(0) lebih akurat dan mematuhi standar ANSI dan ISO 8601.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cara melihat riwayat kueri di SQL Server Management Studio

  2. 2 Cara Mengembalikan Nama Server di SQL Server (T-SQL)

  3. Bagaimana cara mengembalikan beberapa nilai dalam satu kolom (T-SQL)?

  4. Pencocokan Fuzzy SQL

  5. Memantau Penghitung Kinerja melalui PERFMON | Pemecahan Masalah Kinerja SQL Server -3