Ketika Anda mulai mendapatkan "bidang yang ditentukan pengguna" seperti yang sering ditemukan di pelacak bug, manajemen sumber daya pelanggan, dan alat bisnis serupa adalah bahwa mereka tidak didukung dengan tabel dengan bidang bajillion (jika ya, maka kemungkinan masalah itu sendiri).
Alih-alih apa yang Anda temukan adalah desain tabel Nilai Atribut Entitas dan alat administrasi terkait untuk mengelola atribut yang valid.
Pertimbangkan tabel berikut:
+ -------------- +
| hal |
| -------------- |
| id |
| ketik |
| desc |
| attr1 |
| attr2 |
| attr3 |
| attr4 |
| attr5 |
+ -------------- +
Ini setelah Anda menambahkan beberapa atribut. Alih-alih attr1
berpura - pura membaca artist
atau tracks
atau genre
atribut apa pun yang dimiliki benda itu. Dan bukannya 5, bagaimana jika itu 50. Jelas itu tidak bisa diatur. Ini juga memerlukan pembaruan model dan pemindahan aplikasi untuk menangani bidang baru. Tidak ideal
Sekarang perhatikan struktur tabel berikut:
+ -------------- + + --------------- + + ------------- +
| hal | | thing_attr | | attr |
| -------------- | | --------------- | | ------------- |
| id | <--- + | thing_id (fk) | +> | id |
| ketik | | attr_id (fk) | + - + | nama |
| desc | | nilai | | |
+ -------------- + + --------------- + + ------------- +
Anda mendapatkan barang Anda dengan bidang dasarnya. Anda memiliki dua tabel lagi. Satu dengan atribut. Setiap bidang adalah baris dalam attr
tabel. Dan kemudian ada thing_attr
dengan sepasang kunci asing yang berkaitan kembali ke thing
meja dan attr
meja. Dan ini kemudian memiliki bidang nilai tempat Anda menyimpan nilai bidang apa pun untuk entitas itu nantinya.
Dan sekarang Anda punya struktur di mana tabel attr dapat diperbarui saat runtime dan bidang baru dapat ditambahkan (atau dihapus) dengan cepat tanpa dampak signifikan pada keseluruhan aplikasi.
Pertanyaannya sedikit lebih kompleks dan validasi menjadi lebih kompleks juga (baik prosedur tersimpan yang funky atau semua sisi klien). Ini adalah trade off dalam desain.
Pertimbangkan juga situasi di mana suatu hari Anda perlu melakukan migrasi dan Anda kembali ke aplikasi untuk menemukan bahwa sekarang ada setengah lusin atribut atau lebih dari skema yang Anda bagikan pada awalnya. Ini membuat migrasi dan pemutakhiran yang buruk di mana tabel Nilai Atribut Entitas, bila digunakan dengan benar, bisa lebih bersih. (Tidak selalu, tetapi bisa.)
Apakah ada kerugian untuk hanya memodifikasi skema saat runtime? Jika pengguna berpikir suatu hal memerlukan atribut baru, cukup tambahkan kolom secara dinamis ke tabel?
Jika Anda bekerja dengan citarasa yang sesuai dari database nosql, Anda mungkin bisa melakukan ini (perhatikan bahwa citarasa yang tepat dari nosql untuk ini mungkin akan menjadi toko nilai kunci yang, yah, tabel EAV untuk yang berhubungan seperti dijelaskan di atas) tanpa terlalu banyak kesulitan. Namun ia datang dengan semua kompromi untuk nosql yang dijelaskan di tempat lain dengan sangat rinci.
Jika Anda bekerja pada basis data relasional - Anda harus memiliki skema. Menambahkan kolom secara dinamis berarti beberapa bagian dari hal-hal berikut ini benar:
- Anda sedang melakukan pemrograman meta-database. Alih-alih dapat memetakan kolom ini dengan bersih ke bidang itu dengan ORM yang bagus, Anda mungkin melakukan hal-hal seperti
select *
dan kemudian melakukan beberapa kode kompleks untuk mengetahui apa sebenarnya data tersebut (lihat ResultSetMetaData Java ) dan kemudian menyimpannya di peta ( atau tipe data lain - tetapi bidang yang tidak bagus dalam kode). Ini kemudian membuang sedikit jenis dan keamanan kesalahan ketik yang Anda miliki dengan pendekatan tradisional.
- Anda kemungkinan telah meninggalkan ORM. Ini berarti Anda menulis sql mentah untuk semua kode alih-alih membiarkan sistem bekerja untuk Anda.
- Anda sudah menyerah melakukan peningkatan bersih. Apa yang terjadi ketika pelanggan menambahkan bidang dengan satu nama yang juga digunakan oleh versi Anda selanjutnya? Di situs perjodohan, pemutakhiran yang ingin menambahkan
hasdate
bidang untuk menyimpan stempel waktu telah didefinisikan sebagai hasdate
boolean untuk kecocokan yang berhasil ... dan pemutakhiran Anda rusak.
- Anda percaya bahwa pelanggan tidak merusak sistem dengan menggunakan kata khusus yang merusak permintaan Anda juga ... di suatu tempat.
- Anda mengikat diri Anda pada satu merek basis data. The DDL dari database yang berbeda berbeda. Jenis basis data adalah contoh termudah dari ini.
varchar2
vs text
dan sejenisnya. Kode Anda untuk menambahkan kolom akan berfungsi pada MySQL tetapi tidak pada Postgres atau Oracle atau SQL Server.
- Apakah Anda percaya pelanggan benar-benar menambahkan data dengan baik ? Tentu, EAV jauh dari ideal tetapi sekarang Anda punya beberapa nama tabel yang tidak dikenal yang tidak ditambahkan oleh pengembang Anda, dengan jenis indeks yang salah (jika ada), tanpa kendala ditambahkan dalam kode di mana perlu menjadi dan seterusnya.
- Anda telah memberikan hak istimewa skema modifikasi kepada pengguna yang menjalankan aplikasi. Little Bobby Drop Tables tidak mungkin ketika Anda dibatasi untuk SQL daripada DDL (tentu saja Anda dapat melakukannya
delete * from students
, tetapi Anda tidak dapat mengacaukan database dengan cara yang buruk). Jumlah hal yang bisa salah dengan akses skema baik dari kecelakaan atau meroketnya aktivitas jahat.
Ini benar-benar bermuara pada "jangan lakukan itu." Jika Anda benar-benar menginginkan ini, lakukan dengan pola struktur tabel EAV yang diketahui atau database yang sepenuhnya didedikasikan untuk struktur ini. Jangan biarkan orang membuat bidang sembarang dalam tabel. Sakit kepala tidak layak.