Tipe numerik menentukan cara MySQL menyimpan bilangan, batas nilai yang diterima, tingkat presisinya, serta reaksi server ketika nilai yang dimasukkan melewati batas kolom. Topik ini membahas lima tipe bilangan bulat dari TINYINT sampai BIGINT, atribut UNSIGNED yang menggeser rentang ke nilai non-negatif, serta pemilihan antara DECIMAL dan DOUBLE untuk nilai uang. Setiap perilaku didemonstrasikan pada MySQL 8.0 lewat klien mysql, termasuk error yang muncul ketika nilai di luar rentang dimasukkan dalam strict mode. Hasil akhirnya adalah dasar pemilihan tipe yang berpijak pada perilaku nyata, bukan pada perkiraan.
Keluarga tipe bilangan bulat#
MySQL menyediakan lima tipe bilangan bulat, yaitu TINYINT, SMALLINT, MEDIUMINT, INT, dan BIGINT. Kelimanya menyimpan bilangan tanpa bagian pecahan dan berbeda hanya pada jumlah byte penyimpanan serta rentang nilainya. Tabel berikut merangkum rentang bertanda (signed) dan tanpa tanda (unsigned) setiap tipe menurut manual MySQL 8.0.
| Tipe | Penyimpanan | Rentang bertanda | Rentang tanpa tanda |
|---|---|---|---|
TINYINT | 1 byte | -128 sampai 127 | 0 sampai 255 |
SMALLINT | 2 byte | -32768 sampai 32767 | 0 sampai 65535 |
MEDIUMINT | 3 byte | -8388608 sampai 8388607 | 0 sampai 16777215 |
INT | 4 byte | -2147483648 sampai 2147483647 | 0 sampai 4294967295 |
BIGINT | 8 byte | -9223372036854775808 sampai 9223372036854775807 | 0 sampai 18446744073709551615 |
Prinsip pemilihannya adalah mengambil tipe terkecil yang rentangnya masih menampung nilai terburuk yang mungkin, dengan ruang untuk pertumbuhan data. Kolom nilai ujian dengan rentang 0 sampai 100 cukup memakai TINYINT, sedangkan penghitung baris pada tabel besar layak memakai BIGINT karena INT berhenti pada 2147483647. Tipe INT sering menjadi pilihan bawaan, tetapi ukuran yang tidak diperhitungkan hanya menunda masalah, bukan menghilangkannya. Apabila ada keraguan antara dua tipe, perkiraan kebutuhan data sampai sepuluh tahun ke depan menjadi penentu yang lebih aman daripada kebiasaan menyalin skema lama.
Atribut UNSIGNED#
Atribut UNSIGNED diletakkan setelah nama tipe untuk melarang nilai negatif dan menggeser seluruh rentang ke bilangan tak negatif, sehingga TINYINT UNSIGNED menerima 0 sampai 255 alih-alih -128 sampai 127. Atribut ini tepat untuk kolom yang secara semantik memang tidak mungkin negatif, seperti nilai ujian, jumlah stok, atau durasi. Demonstrasi berikut membuat tabel nilai ujian dengan kolom bertipe TINYINT UNSIGNED, mengisinya dengan tiga baris, kemudian mencoba memasukkan nilai 300 yang berada di luar rentang.
-- tidak-dijalankan
DROP DATABASE IF EXISTS latihan_tipe;
CREATE DATABASE latihan_tipe;
USE latihan_tipe;
CREATE TABLE nilai_ujian (
siswa VARCHAR(40) NOT NULL,
nilai TINYINT UNSIGNED NOT NULL
);
INSERT INTO nilai_ujian VALUES
('Ali', 88),
('Budi', 74),
('Citra', 95);# membuat ulang basis data latihan dan tabelnya
mysql -u root < skema-nilai.sqlSisipan dengan nilai 300 menimbulkan error, bukan penyimpanan yang diam-diam dipotong.
# mencoba memasukkan nilai di luar rentang TINYINT UNSIGNED
mysql -u root latihan_tipe -e "INSERT INTO nilai_ujian VALUES ('Dewi', 300);"ERROR 1264 (22003) at line 1: Out of range value for column 'nilai' at row 1MySQL 8.0 menjalankan strict mode secara default, yakni mode server yang menolak data tidak sah dengan error 1264 seperti di atas. Pada konfigurasi lama tanpa mode strict, nilai yang sama dipotong ke 255 dan hanya memunculkan warning yang mudah terlewat. Data yang tersimpan tetap konsisten, sehingga pernyataan berikutnya dapat menampilkan isinya.
# menampilkan isi tabel nilai_ujian
mysql -t -u root latihan_tipe -e "SELECT * FROM nilai_ujian;"+-------+-------+
| siswa | nilai |
+-------+-------+
| Ali | 88 |
| Budi | 74 |
| Citra | 95 |
+-------+-------+DECIMAL untuk nilai yang presisi#
Tipe DOUBLE menyimpan bilangan pecahan dalam format biner IEEE 754 dan kinerjanya cepat. Namun, banyak nilai desimal yang tidak dapat dinyatakan tepat dalam biner, sehingga hasil aritmetikanya mendekati nilai yang benar tanpa pernah menyentuhnya persis. Tipe DECIMAL(M,D) berbeda, yaitu MySQL menyimpannya sebagai deretan digit dengan M digit total dan D digit di belakang tanda desimal, sehingga aritmetikanya eksak. Untuk nilai uang, selisih kecil yang menumpuk pada ribuan operasi bukan hal yang dapat diterima, sehingga DECIMAL menjadi pilihan bawaan untuk kolom moneter.
Demonstrasi berikut membuat tabel cicilan dengan dua kolom bernilai sama, satu bertipe DECIMAL(6,2) dan satu bertipe DOUBLE, lalu menjumlahkan sepuluh baris senilai 0.10 pada masing-masing kolom.
# membuat tabel cicilan dan menjumlahkan sepuluh nilai 0.10
mysql -t -u root latihan_tipe <<'SQL'
CREATE TABLE cicilan (
ke INT PRIMARY KEY,
nilai_desimal DECIMAL(6,2) NOT NULL,
nilai_ganda DOUBLE NOT NULL
);
INSERT INTO cicilan VALUES
(1,0.10,0.10),(2,0.10,0.10),(3,0.10,0.10),(4,0.10,0.10),(5,0.10,0.10),
(6,0.10,0.10),(7,0.10,0.10),(8,0.10,0.10),(9,0.10,0.10),(10,0.10,0.10);
SELECT SUM(nilai_desimal) AS total_desimal, SUM(nilai_ganda) AS total_ganda
FROM cicilan;
SQL+---------------+--------------------+
| total_desimal | total_ganda |
+---------------+--------------------+
| 1.00 | 0.9999999999999999 |
+---------------+--------------------+Kolom DECIMAL menghasilkan 1.00 persis, sedangkan kolom DOUBLE menghasilkan 0.9999999999999999. Selisih sebesar ini mungkin tampak sepele, tetapi pola yang sama muncul pada setiap penjumlahan bilangan yang tidak dapat dinyatakan dalam biner. Ekspresi literal berikut menunjukkan perbandingan yang sering dikutip, yaitu penjumlahan 0.1 dengan 0.2, beserta pembulatan nilai 10.105 ke DECIMAL(8,2).
# membandingkan aritmetika desimal dan biner lalu menguji pembulatan
mysql -t -u root -e "SELECT 0.1 + 0.2 AS desimal, 0.1e0 + 0.2e0 AS ganda; SELECT CAST(10.105 AS DECIMAL(8,2)) AS dibulatkan;"+---------+---------------------+
| desimal | ganda |
+---------+---------------------+
| 0.3 | 0.30000000000000004 |
+---------+---------------------+
+------------+
| dibulatkan |
+------------+
| 10.11 |
+------------+Akar perbedaannya terletak pada representasi. Literal 0.1 tanpa eksponen diperlakukan sebagai DECIMAL dan dihitung dengan aritmetika desimal, sedangkan 0.1e0 dengan eksponen diperlakukan sebagai DOUBLE. Pembulatan CAST menjadikan 10.105 sebagai 10.11 karena kolom tujuan hanya menampung dua digit pecahan. Ketika kolom memang dideklarasikan sebagai desimal eksak, perilaku pembulatan seperti ini mudah diprediksi dan dapat diuji.
Kesalahan umum#
Kesalahan pada pemilihan tipe numerik jarang terasa saat tabel dibuat dan baru muncul ketika data bertumpuk. Tiga kesalahan berikut paling sering ditemukan beserta perbaikannya.
- Menyimpan nilai uang di
DOUBLE. Penyebabnya adalah kebiasaan memilih tipe pecahan yang paling umum tanpa mempertimbangkan presisi, sehingga penjumlahan seperti pada bagian sebelumnya menghasilkan angka yang bergeser sedikit dan perbandingan kesetaraan menjadi tidak dapat diandalkan. Perbaikannya adalah memindahkan kolom moneter keDECIMALdengan skala yang sesuai kebutuhan, misalnyaDECIMAL(12,2). - Mengandalkan
UNSIGNEDuntuk mencegah hasil negatif dari perhitungan. Pengurangan yang menghasilkan nilai di bawah nol pada ekspresiUNSIGNEDmemunculkan error1690, seperti pada perintah berikut.
# mencoba mengurangi nilai UNSIGNED melewati nol
mysql -u root latihan_tipe -e "SELECT CAST(0 AS UNSIGNED) - 1;"ERROR 1690 (22003) at line 1: BIGINT UNSIGNED value is out of range in '(cast(0 as unsigned) - 1)'Perbaikannya bukan menghapus atribut UNSIGNED, melainkan memastikan logika aplikasi tidak pernah mengurangkan melewati nol, atau menggunakan tipe bertanda bila nilai negatif memang mungkin terjadi.
- Menganggap
TINYINT(1)sebagai tipe boolean tersendiri. Angka di dalam tanda kurung hanyalah lebar tampilan dan tidak mengubah rentang maupun penyimpanan, sehinggaTINYINT(1)tetap menyimpan bilangan bulat -128 sampai 127. Sejak MySQL 8.0.17 lebar tampilan untuk tipe bilangan bulat berstatus deprecated, sehingga kebiasaan menuliskannya sebaiknya ditinggalkan. Konvensi yang lebih jelas adalahTINYINT UNSIGNEDdengan nilai 0 dan 1, atau mengandalkan konversi yang dilakukan driver aplikasi.
Ringkasan#
- Lima tipe bilangan bulat MySQL berbeda pada penyimpanan dan rentang, dari
TINYINTsatu byte sampaiBIGINTdelapan byte, sehingga tipe terkecil yang menampung kebutuhan adalah pilihan yang tepat. - Atribut
UNSIGNEDmelarang nilai negatif dan menggandakan rentang atas, tetapi bukan pengganti validasi aplikasi. - Dalam strict mode bawaan MySQL 8.0, nilai di luar rentang ditolak dengan error
1264, bukan dipotong diam-diam. DECIMAL(M,D)menghitung secara eksak dan menjadi pilihan kolom uang, sedangkanDOUBLEmenyimpan pendekatan biner yang membuat 0.1 plus 0.2 menghasilkan 0.30000000000000004.
Referensi#
- Numeric Types — MySQL 8.0 Reference Manual — Rentang dan kebutuhan penyimpanan setiap tipe numerik.
- DECIMAL Data Type Characteristics — MySQL 8.0 Reference Manual — Deklarasi DECIMAL(M,D) dan sifat eksak aritmetikanya.
- Out-of-Range and Overflow Handling — MySQL 8.0 Reference Manual — Perilaku mode strict terhadap nilai di luar rentang.