Sebagian data memang bukan teks: hash password, token sesi acak, checksum file, hingga isi file gambar itu sendiri. Untuk data mentah seperti itu MySQL menyediakan keluarga tipe biner — BINARY, VARBINARY, dan BLOB — yang menyimpan byte apa adanya tanpa character set maupun collation. Pada Chapter ini kita akan membandingkan BINARY dengan VARBINARY lewat padding byte nol yang khas, memakai HEX() dan UNHEX() untuk melihat byte yang tersimpan, lalu mempraktikkan pola penyimpanan hash yang dipakai aplikasi nyata.

BINARY vs VARBINARY #

BINARY(n) menyimpan n byte dengan panjang tetap — bila isinya lebih pendek, MySQL menambahkan byte nol (0x00) hingga penuh. VARBINARY(n) menyimpan byte dengan panjang variabel maksimal n tanpa penambahan apa pun. Keduanya adalah kembaran CHAR/VARCHAR, hanya saja isinya byte mentah yang tidak ditafsirkan sebagai karakter. Karena byte nol tidak bisa kita ketik di terminal, kita bekerja memakai fungsi UNHEX() untuk membangun byte dari teks heksadesimal dan HEX() untuk membacanya kembali:

sql
DROP DATABASE IF EXISTS belajar_tipe;
CREATE DATABASE belajar_tipe;
USE belajar_tipe;

Output yang Dihasilkan:

text
Query OK, 0 rows affected, 1 warning (0.00 sec)

Query OK, 1 row affected (0.00 sec)

Database changed
sql
CREATE TABLE sesi (
  id INT,
  kode BINARY(8),
  token VARBINARY(16)
);

INSERT INTO sesi VALUES (1, UNHEX('DEADBEEF'), UNHEX('CAFEBABE'));

SELECT id,
       HEX(kode) AS byte_kode,
       HEX(token) AS byte_token,
       LENGTH(kode) AS panjang_kode,
       LENGTH(token) AS panjang_token
FROM sesi;

Output yang Dihasilkan:

text
Query OK, 0 rows affected (0.00 sec)

Query OK, 1 row affected (0.00 sec)

+------+------------------+------------+--------------+---------------+
| id   | byte_kode        | byte_token | panjang_kode | panjang_token |
+------+------------------+------------+--------------+---------------+
|    1 | DEADBEEF00000000 | CAFEBABE   |            8 |             4 |
+------+------------------+------------+--------------+---------------+
1 row in set (0.00 sec)

Mari kita bedah hasilnya. Kita memasukkan 4 byte DEADBEEF ke kode BINARY(8) dan 4 byte CAFEBABE ke token VARBINARY(16). Pembacaan HEX() memperlihatkan perbedaan perlakuan: kode tampil sebagai DEADBEEF00000000 — empat byte nol ditambahkan hingga penuh 8 byte — sedangkan token tampil CAFEBABE tanpa tambahan apa pun. Kolom LENGTH mengonfirmasi: 8 byte versus 4 byte. Padding byte nol pada BINARY ini sejajar dengan padding spasi pada CHAR, hanya saja byte nol tidak pernah dipangkas saat dibaca — apa yang tersimpan, itulah yang keluar.

Padding ini punya konsekuensi pada pembanding. Nilai BINARY(8) berisi DEADBEEF00000000 tidak sama dengan 4 byte polos DEADBEEF:

sql
SELECT HEX(kode) = 'DEADBEEF00000000' AS sama_dengan_padding,
       HEX(kode) = 'DEADBEEF' AS sama_tanpa_padding
FROM sesi;

Output yang Dihasilkan:

text
+---------------------+--------------------+
| sama_dengan_padding | sama_tanpa_padding |
+---------------------+--------------------+
|                   1 |                  0 |
+---------------------+--------------------+
1 row in set (0.00 sec)

Pembanding pertama menghasilkan 1 karena kedua sisi memang 8 byte identik, sedangkan pembanding kedua menghasilkan 0 — byte nol penambat dihitung sebagai bagian dari data. Inilah alasan VARBINARY jauh lebih umum dipakai untuk token dan identifier acak: panjang isinya bervariasi dan kita tidak ingin byte nol ikut menyusup ke pembanding. BINARY(n) lebih cocok untuk data yang memang selalu berukuran tetap, misalnya hash yang selalu 32 byte.

HEX dan UNHEX sebagai Kacamata #

Dua fungsi ini menjadi pasangan wajib saat bekerja dengan data biner. UNHEX('DEADBEEF') membaca teks heksadesimal dua karakter per byte dan menghasilkan 4 byte mentah; HEX() melakukan kebalikannya dengan deterministik penuh — input yang sama selalu menghasilkan byte yang sama, dan byte yang sama selalu tampil sebagai teks heksadesimal yang sama. Berkat sifat deterministik itu, HEX() aman dipakai untuk memverifikasi isi kolom biner dalam pengujian maupun audit, dan teks heksadesimal menjadi format pengiriman data biner yang lazim (misalnya pada log dan dump).

Sebagai bonus, HEX() juga bisa dipakai untuk melihat representasi byte dari teks biasa. Misalnya HEX('A') menghasilkan 41 (kode ASCII huruf A) — trik yang berguna saat menyelidiki perbedaan halus seperti karakter tersembunyi di data teks.

Keluarga BLOB untuk Data Besar #

Untuk data biner yang bisa besar — gambar, lampiran, dump — keluarga BLOB (Binary Large Object) menyediakan wadah dengan batas yang sama persis dengan keluarga TEXT:

TipeUkuran maksimalContoh pemakaian
TINYBLOB255 bytechecksum kecil, flag biner
BLOB65.535 bytetoken panjang, gambar kecil
MEDIUMBLOB16.777.215 bytefoto, dokumen PDF
LONGBLOB4.294.967.295 bytevideo, berkas besar

BLOB pada dasarnya adalah VARBINARY tanpa panjang maksimal yang kita tentukan — isinya disimpan variabel sesuai ukuran aslinya. Pola pemakaian paling umum di aplikasi: menyimpan hash password. Fungsi SHA2(teks, 256) menghasilkan hash 64 karakter heksadesimal; dengan UNHEX() kita memampatkannya menjadi 32 byte yang tepat muat di BINARY(32):

sql
CREATE TABLE pengguna (
  id INT,
  nama VARCHAR(40),
  password_hash BINARY(32)
);

INSERT INTO pengguna VALUES
  (1, 'Budi', UNHEX(SHA2('rahasia-latihan', 256))),
  (2, 'Siti', UNHEX(SHA2('sandi-belajar', 256)));

SELECT id, nama, HEX(password_hash) AS hash_tersimpan FROM pengguna ORDER BY id;

Output yang Dihasilkan:

text
Query OK, 0 rows affected (0.00 sec)

Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

+------+------+------------------------------------------------------------------+
| id   | nama | hash_tersimpan                                                   |
+------+------+------------------------------------------------------------------+
|    1 | Budi | 0650DBB2B511B784B2464D6EFA4B132755739FD49598212D29C364732A909293 |
|    2 | Siti | 444FDEEC3865CC301D0FC34A149CC6F13991ACF0892BF8FCC2E574797BDB0F8B |
+------+------+------------------------------------------------------------------+
2 rows in set (0.00 sec)

Hash setiap pengguna tersimpan sebagai 32 byte biner dan dibaca kembali sebagai 64 karakter heksadesimal — panjang kolom password_hash yang tepat membuat UNHEX(SHA2(...)) selalu muat tanpa padding. Pola ini hemat setengah ruang dibanding menyimpan teks heksadesimal di CHAR(64), dan pada tabel berjuta baris penghematannya nyata terasa. Untuk verifikasi login, aplikasi cukup menghitung SHA2() dari sandi yang dimasukkan lalu membandingkan UNHEX()-nya dengan kolom ini.

Terakhir, kita bereskan database latihan:

sql
DROP DATABASE belajar_tipe;

Output yang Dihasilkan:

text
Query OK, 2 rows affected (0.00 sec)

Referensi #

Seluruh keluarga tipe data kini sudah kita jelajahi satu per satu. Pertanyaan yang tersisa bersifat praktis: ketika mendesain tabel nyata, tipe mana yang dipilih untuk setiap kolom? Chapter berikutnya merangkum semuanya menjadi kerangka keputusan yang siap dipakai.