Database relasional kuat karena data dipecah ke beberapa tabel yang saling berhubungan. Hubungan itu dijaga oleh dua jenis kunci: primary key dan foreign key. Memahaminya dengan benar menentukan apakah datamu konsisten atau penuh duplikasi dan data yatim.
Primary Key (kunci utama)
Primary key adalah kolom (atau gabungan kolom) yang mengidentifikasi satu baris secara unik. Syaratnya:
- Unik: tidak boleh ada dua baris dengan nilai yang sama.
- Tidak boleh NULL.
- Stabil: sebaiknya tidak pernah berubah.
- Ringkas: tipe kecil (integer) lebih cepat dibandingkan teks panjang.
CREATE TABLE pelanggan (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
nama VARCHAR(100) NOT NULL,
email VARCHAR(150) NOT NULL UNIQUE
);
Setiap tabel hanya boleh punya satu primary key. Di InnoDB (mesin penyimpanan bawaan MySQL), primary key juga menentukan urutan fisik data (clustered index), sehingga pencarian berdasarkan PK sangat cepat.
Surrogate key vs natural key
| Jenis | Contoh | Kelebihan | Kekurangan |
|---|---|---|---|
| Surrogate | id auto-increment atau UUID | Stabil, ringkas, tak berarti bisnis | Tidak bermakna bagi manusia |
| Natural | NIK, ISBN, kode produk | Bermakna | Bisa berubah, bisa panjang, aturan bisnis dapat berganti |
Praktik umum: pakai surrogate key sebagai PK, dan beri batasan UNIQUE pada natural key (misalnya email atau NIK) agar tidak terduplikasi.
Composite key
PK dari gabungan beberapa kolom, umum pada tabel penghubung:
CREATE TABLE siswa_kelas (
siswa_id BIGINT UNSIGNED,
kelas_id BIGINT UNSIGNED,
PRIMARY KEY (siswa_id, kelas_id)
);
Foreign Key (kunci tamu)
Foreign key adalah kolom yang merujuk ke primary key tabel lain. Ia menjamin bahwa nilai yang dirujuk benar-benar ada.
CREATE TABLE pesanan (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
pelanggan_id BIGINT UNSIGNED NOT NULL,
total DECIMAL(12,2) NOT NULL,
FOREIGN KEY (pelanggan_id) REFERENCES pelanggan(id)
);
Dengan aturan ini, database menolak:
- menambah pesanan untuk
pelanggan_idyang tidak ada; - menghapus pelanggan yang masih memiliki pesanan (sesuai aksi yang kamu pilih).
Tipe data kolom FK harus sama persis dengan PK yang dirujuk (misalnya sama-sama BIGINT UNSIGNED), kalau tidak pembuatan constraint akan gagal.
Aksi referensial: ON DELETE dan ON UPDATE
Menentukan apa yang terjadi pada baris "anak" saat baris "induk" dihapus:
| Aksi | Perilaku | Contoh penggunaan |
|---|---|---|
RESTRICT / NO ACTION | Tolak penghapusan jika masih ada anak | Pelanggan yang punya pesanan |
CASCADE | Anak ikut terhapus | Item pesanan saat pesanan dihapus |
SET NULL | Kolom FK anak diisi NULL (kolom harus boleh NULL) | Kategori dihapus, produk tetap ada |
SET DEFAULT | Diisi nilai bawaan | Jarang dipakai |
FOREIGN KEY (pesanan_id) REFERENCES pesanan(id) ON DELETE CASCADE
Hati-hati dengan CASCADE: satu perintah hapus bisa menghilangkan banyak data sekaligus. Gunakan hanya untuk data yang memang tidak bermakna tanpa induknya.
Jenis relasi
- Satu-ke-banyak (1:N): satu pelanggan punya banyak pesanan. FK ada di sisi "banyak".
- Satu-ke-satu (1:1): pengguna dan profilnya. FK dengan batasan
UNIQUE. - Banyak-ke-banyak (N:M): siswa dan kelas. Butuh tabel penghubung (pivot) berisi dua FK.
Dasar normalisasi
Normalisasi adalah proses merapikan tabel untuk mengurangi duplikasi:
- 1NF: setiap sel berisi satu nilai (jangan simpan "Matematika, Fisika" dalam satu kolom).
- 2NF: semua kolom bergantung pada seluruh PK (relevan untuk composite key).
- 3NF: kolom non-kunci tidak bergantung pada kolom non-kunci lain. Contoh: jangan menyimpan
nama_kotadankode_posbersama di tabel pelanggan jika kode pos menentukan kota; pindahkan ke tabel tersendiri.
Contoh buruk (duplikasi):
| pesanan_id | nama_pelanggan | alamat_pelanggan |
|---|---|---|
| 1 | Sari | Jl. Merdeka 1 |
| 2 | Sari | Jl. Merdeka 1 |
Jika Sari pindah rumah, kamu harus mengubah banyak baris dan mudah terlewat. Solusinya: simpan pelanggan di tabel sendiri dan pesanan hanya menyimpan pelanggan_id.
Praktik terbaik
- Selalu deklarasikan foreign key di database, jangan hanya mengandalkan aplikasi.
- Beri nama konsisten:
pelanggan_idmerujuk kepelanggan.id. - Foreign key otomatis mendapat indeks di InnoDB; ini mempercepat JOIN.
- Pertimbangkan soft delete (kolom
deleted_at) pada data bisnis penting daripada menghapus permanen. - Di Laravel:
$table->foreignId('pelanggan_id')->constrained()->cascadeOnDelete();
Contoh perancangan: sistem perpustakaan
Entitas: Anggota, Buku, Peminjaman. Seorang anggota bisa meminjam banyak buku dan satu buku bisa dipinjam banyak anggota dari waktu ke waktu, jadi relasinya banyak-ke-banyak. Karena itu peminjaman menjadi tabel penghubung yang sekaligus menyimpan data tambahan.
CREATE TABLE anggota (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
nama VARCHAR(100) NOT NULL,
nomor_anggota VARCHAR(20) NOT NULL UNIQUE
);
CREATE TABLE buku (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
judul VARCHAR(200) NOT NULL,
isbn VARCHAR(20) UNIQUE
);
CREATE TABLE peminjaman (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
anggota_id BIGINT UNSIGNED NOT NULL,
buku_id BIGINT UNSIGNED NOT NULL,
dipinjam_pada DATE NOT NULL,
dikembalikan_pada DATE NULL,
FOREIGN KEY (anggota_id) REFERENCES anggota(id) ON DELETE RESTRICT,
FOREIGN KEY (buku_id) REFERENCES buku(id) ON DELETE RESTRICT
);
Keputusan desain yang patut diperhatikan:
nomor_anggotadanisbnadalah natural key yang diberiUNIQUE, tetapi PK tetapidsurrogate.ON DELETE RESTRICTmencegah penghapusan anggota atau buku yang masih punya riwayat peminjaman.dikembalikan_padabernilaiNULLselama buku belum dikembalikan; query "buku yang sedang dipinjam" cukupWHERE dikembalikan_pada IS NULL.
Apa yang terjadi saat constraint dilanggar?
-- Anggota 999 tidak ada
INSERT INTO peminjaman (anggota_id, buku_id, dipinjam_pada) VALUES (999, 1, CURDATE());
-- ERROR 1452: Cannot add or update a child row: a foreign key constraint fails
-- Menghapus anggota yang punya riwayat
DELETE FROM anggota WHERE id = 1;
-- ERROR 1451: Cannot delete or update a parent row: a foreign key constraint fails
Error ini bukan gangguan; justru itulah perlindungan yang mencegah data yatim.
Foreign key dan performa
- Foreign key butuh index pada kolom FK; InnoDB membuatnya otomatis jika belum ada.
- Pengecekan FK menambah sedikit biaya pada INSERT/UPDATE/DELETE, tetapi manfaat integritasnya jauh lebih besar untuk hampir semua aplikasi.
- Pada sistem yang sangat besar (sharding), sebagian tim melepas FK dan menjaga integritas di aplikasi. Itu keputusan lanjutan yang punya konsekuensi; bagi pemula, gunakan FK.
Pertanyaan untuk menguji pemahamanmu
- Mengapa kolom
emailyang UNIQUE tidak dijadikan primary key? - Apa yang terjadi jika tipe
anggota_iddipeminjamanadalahINTsedangkananggota.idadalahBIGINT UNSIGNED? - Kapan
ON DELETE CASCADEtepat, dan kapan berbahaya? - Bagaimana merancang relasi satu produk punya banyak kategori dan satu kategori berisi banyak produk?
Kesimpulan
Primary key menjawab "baris mana ini?", foreign key menjawab "baris ini milik siapa?". Gunakan surrogate key yang ringkas, deklarasikan foreign key beserta aksi hapus yang tepat, dan terapkan normalisasi dasar. Hasilnya adalah database yang konsisten dan mudah dikembangkan.
Komentar (0)
Masuk / Daftar