Mengapa Anda menyimpan enum di DB?

69

Saya telah melihat sejumlah pertanyaan, seperti ini , meminta saran tentang cara menyimpan enum di DB. Tetapi saya heran mengapa Anda melakukan itu. Jadi katakanlah saya memiliki entitas Persondengan genderbidang, dan Genderenum. Kemudian, tabel orang saya memiliki jenis kelamin kolom.

Selain alasan yang jelas untuk menegakkan kebenaran, saya tidak melihat mengapa saya akan membuat tabel tambahan genderuntuk memetakan apa yang sudah saya miliki dalam aplikasi saya. Dan saya tidak begitu suka duplikasi itu.

pengguna3748908
sumber
1
Di mana lagi Anda menyimpan data yang dapat berubah secara teratur? Meskipun Anda mungkin telah memikirkan semua opsi, bagaimana jika seseorang datang dan ingin menambahkan opsi baru. Apakah Anda siap untuk men-tweak daftar hard-coded itu? Seseorang mungkin ingin memberikan jenis kelamin mereka sebagai sesuatu selain laki-laki atau perempuan, misalnya interseks misalnya.
JB King
4
@JBKing ... lihat saja daftar jenis kelamin Facebook.
3
Jika pelanggan Anda "tertipu Tumblrites", maka Anda harus membuat skema basis data yang memungkinkan Anda membuat sesuatu yang memenuhi kebutuhan mereka, setidaknya, jika Anda berniat untuk tetap berbisnis.
Gort the Robot

Jawaban:

74

Mari kita ambil contoh lain yang tidak terlalu sarat dengan konsepsi dan harapan. Saya punya enum di sini, dan itu adalah serangkaian prioritas untuk bug.

Nilai apa yang Anda simpan dalam basis data?

Jadi, saya bisa menyimpan 'C', 'H', 'M', dan 'L'dalam database. Atau 'HIGH'dan seterusnya. Ini memiliki masalah data yang diketik dengan ketat . Ada satu set nilai valid yang diketahui, dan jika Anda tidak menyimpan set itu dalam database, mungkin sulit untuk bekerja dengannya.

Mengapa Anda menyimpan data dalam kode?

Anda punya List<String> priorities = {'CRITICAL', 'HIGH', 'MEDIUM', 'LOW'};atau sesuatu yang berpengaruh dalam kode. Ini berarti bahwa Anda memiliki berbagai pemetaan data ini ke format yang tepat (Anda memasukkan semua huruf besar ke dalam basis data, tetapi Anda menampilkannya sebagai Critical). Kode Anda sekarang juga sulit dilokalkan. Anda telah mengikat representasi basis data gagasan ke string yang disimpan dalam kode.

Di mana pun Anda perlu mengakses daftar ini, Anda harus memiliki duplikasi kode atau kelas dengan sekelompok konstanta. Tak satu pun dari itu pilihan yang baik. Orang juga tidak boleh lupa bahwa ada aplikasi lain yang dapat menggunakan data ini (yang dapat ditulis dalam bahasa lain - aplikasi web Java memiliki sistem pelaporan Crystal Reports yang digunakan dan data pekerjaan batch Perl ke dalamnya). Mesin pelaporan perlu mengetahui daftar data yang valid (apa yang terjadi jika tidak ada yang ditandai dalam 'LOW'prioritas dan Anda perlu tahu bahwa itu adalah prioritas yang valid untuk laporan?), Dan pekerjaan batch akan memiliki informasi tentang apa yang valid nilai adalah.

Secara hipotetis, Anda mungkin mengatakan "kami adalah toko satu bahasa - semuanya ditulis dalam Java" dan memiliki .jar tunggal yang berisi informasi ini - tetapi sekarang ini berarti bahwa aplikasi Anda digabungkan secara erat satu sama lain dan .jar yang berisi data. Anda harus merilis bagian pelaporan dan bagian pembaruan kumpulan bersama dengan aplikasi web setiap kali ada perubahan - dan berharap rilis itu berjalan dengan lancar untuk semua bagian.

Apa yang terjadi ketika bos Anda menginginkan prioritas lain?

Bosmu datang hari ini. Ada prioritas baru - CEO. Sekarang Anda harus pergi dan mengubah semua kode dan melakukan kompilasi dan penempatan kembali.

Dengan pendekatan 'enum-in-the-table', Anda memperbarui daftar enum untuk memiliki prioritas baru. Semua kode yang mendapat daftar menariknya dari database.

Data jarang berdiri sendiri

Dengan prioritas, data kunci ke tabel lain yang mungkin berisi informasi tentang alur kerja, atau siapa yang dapat menetapkan prioritas ini atau yang lainnya.

Kembali ke jenis kelamin seperti yang disebutkan dalam pertanyaan sebentar: Jenis kelamin memiliki tautan ke kata ganti yang digunakan: he/his/himdan she/hers/her... dan Anda ingin menghindari pengkodean yang keras ke dalam kode itu sendiri. Dan kemudian bos Anda datang dan Anda perlu menambahkan Anda memiliki 'OTHER'jenis kelamin (untuk membuatnya sederhana) dan Anda perlu menghubungkan jenis kelamin ini dengan they/their/them... dan bos Anda melihat apa yang dimiliki Facebook dan ... yah, ya.

Dengan membatasi diri Anda pada bit data yang diketik secara ketat daripada tabel enum, Anda sekarang harus mereplikasi string itu di banyak tabel lain untuk menjaga hubungan ini antara data dan bit lainnya.

Bagaimana dengan datastore lain?

Di mana pun Anda menyimpan ini, prinsip yang sama ada.

  • Anda dapat memiliki file priorities.prop,, yang memiliki daftar prioritas. Anda membaca daftar ini dari file properti.
  • Anda bisa memiliki database toko dokumen (seperti CouchDB ) yang memiliki entri untuk enums(dan kemudian menulis fungsi validasi dalam JavaScript ):

    {
       "_id": "c18b0756c3c08d8fceb5bcddd60006f4",
       "_rev": "1-c89f76e36b740e9b899a4bffab44e1c2",
       "priorities": [ "critical", "high", "medium", "low" ],
       "severities": [ "blocker", "bad", "annoying", "cosmetic" ]
    }
    
  • Anda dapat memiliki file XML dengan sedikit skema:

    <xs:element name="priority" type="priorityType"/>
    
    <xs:simpleType name="priorityType">
      <xs:restriction base="xs:string">
        <xs:enumeration value="critical"/>
        <xs:enumeration value="high"/>
        <xs:enumeration value="medium"/>
        <xs:enumeration value="low"/>
      </xs:restriction>
    </xs:simpleType>
    

Ide intinya sama. Menyimpan data itu sendiri adalah tempat daftar nilai yang valid perlu disimpan dan ditegakkan. Dengan menempatkannya di sini, lebih mudah untuk memberi alasan tentang kode dan data. Anda tidak perlu khawatir untuk secara defensif memeriksa apa yang Anda miliki setiap waktu (apakah ini huruf besar? Atau lebih rendah? Mengapa ada chriticaljenis dalam kolom ini? Dll ...) karena Anda tahu apa yang Anda dapatkan dari datastore adalah persis apa yang diharapkan oleh datastore Anda untuk dikirim sebaliknya - dan Anda dapat meminta datastore untuk daftar nilai yang valid.

Dibawa pulang

Himpunan nilai yang valid adalah data , bukan kode. Anda tidak perlu berusaha untuk DRY kode - tetapi masalah duplikasi adalah bahwa Anda menduplikasi data yang dalam kode, daripada menghormati tempatnya sebagai data dan menyimpannya dalam database.

Itu membuat menulis beberapa aplikasi terhadap datastore lebih mudah dan menghindari memiliki contoh di mana Anda akan perlu menyebarkan segala sesuatu yang tergabung erat dengan data itu sendiri - karena Anda belum menambahkan kode Anda ke data.

Itu membuat pengujian aplikasi lebih mudah karena Anda tidak perlu menguji ulang seluruh aplikasi ketika CEOprioritas ditambahkan - karena Anda tidak memiliki kode apa pun yang peduli tentang nilai aktual prioritas.

Mampu beralasan tentang kode dan data secara independen dari satu sama lain membuatnya lebih mudah untuk menemukan dan memperbaiki bug saat melakukan pemeliharaan.

Peter Mortensen
sumber
6
Jika Anda dapat menambahkan nilai enum ke kode Anda tanpa harus mengubah logika apa pun (dan jangan-jangan itu tampilan terlokalisasi darinya), saya meragukan perlunya nilai enum tambahan di tempat pertama. Dan sementara saya sudah cukup tua untuk menilai kemampuan untuk dengan mudah meminta backup database dengan query SQL sederhana untuk menganalisis masalah, dengan ORM hari ini Anda dapat melakukannya dengan sangat baik tanpa harus melihat database yang mendasarinya sama sekali. Saya tidak mengerti poin tentang pelokalan (kata ganti) di sini - hal-hal itu tentu tidak boleh dalam database, tetapi file sumber daya dari beberapa jenis saya akan katakan.
Voo
1
@Vo, kata ganti adalah contoh dari data lain yang terkait dengan nilai enumesque ini. Tanpa data dalam tabel, nilai-nilai yang diketik secara ketat harus ada di sana tanpa batasan FK yang tepat. Jika Anda memiliki kata ganti (seperti ini) dalam file sumber daya, Anda harus menyambungkan antara database dan file (perbarui database dan gunakan kembali file tersebut). Pertimbangkan enum redmine yang dapat dimodifikasi melalui antarmuka admin dengan cepat tanpa harus melakukan penempatan ulang.
1
... ingat juga bahwa basis data adalah penyimpan data polyglot. Jika Anda memerlukan validasi untuk dilakukan sebagai bagian dari ORM dalam satu bahasa, Anda telah membuatnya perlu untuk menggandakan validasi itu dalam bahasa lain yang Anda gunakan (Saya baru-baru ini bekerja dengan ujung depan Java yang memiliki Python mendorong data ke dalam database - Java ORM dan sistem Python harus menyetujui hal-hal - dan perjanjian itu (tipe yang valid) paling mudah diimplementasikan dengan meminta database menegakkannya dengan tabel 'enum'.).
2
@Vo, penggunaan Redumine pada enum sama dengan bugzilla "tabel paling penting berisi semua bug sistem. Ini terdiri dari berbagai properti bug termasuk semua nilai enum seperti keparahan dan prioritas." - Ini bukan bidang teks formulir gratis, ini adalah nilai yang merupakan salah satu dari rangkaian yang diketahui dan dapat dihitung ini. Ini bukan enum waktu kompilasi , tetapi masih enumish. Lihat juga Mantis .
1
Jadi untuk mengkonfirmasi - maksud Anda adalah bahwa orang tidak boleh menggunakan Enums? Tidak jelas.
niico
18

Menurut Anda, manakah di antara ini yang lebih cenderung menghasilkan kesalahan saat membaca kueri?

select * 
from Person 
where Gender = 1

Atau

select * 
from Person join Gender on Person.Gender = Gender.GenderId
where Gender.Label = "Female" 

Orang-orang membuat tabel enum dalam SQL karena mereka menemukan yang terakhir lebih mudah dibaca - menyebabkan lebih sedikit kesalahan dalam menulis dan memelihara SQL.

Anda dapat membuat gender menjadi string secara langsung Person, tetapi kemudian Anda harus mencoba dan menegakkan kasus. Anda juga dapat meningkatkan hit penyimpanan untuk tabel dan waktu kueri karena perbedaan antara string dan integer tergantung pada seberapa hebat DB Anda dalam mengoptimalkan berbagai hal.

Telastyn
sumber
5
Tapi kemudian kita bergabung dengan tabel. Jika entitas saya memiliki dua enum, saya akan bergabung dengan tiga tabel hanya untuk permintaan sederhana.
user3748908
11
@ user3748908 - jadi? Bergabung adalah keahlian DB, dan alternatifnya lebih buruk - setidaknya di mata orang yang memilih rute ini.
Telastyn
8
@ user3748908: Tidak hanya basis data yang sangat bagus dalam melakukan penggabungan, mereka juga sangat baik dalam menegakkan konsistensi. Menegakkan konsistensi bekerja sangat, sangat baik ketika Anda bisa mengarahkan kolom di satu tabel di baris pengidentifikasi lainnya dan mengatakan "nilai untuk kolom ini harus menjadi salah satu pengidentifikasi dalam tabel itu."
Blrfl
2
Ini semua benar tetapi ada banyak kasus di mana Anda harus mengorbankan gabungan untuk alasan kinerja. Jangan salah paham, saya semua tentang jenis desain ini dan bergabung, tetapi saya berpendapat bahwa dunia tidak akan berakhir jika Anda menemukan Anda kadang-kadang tidak perlu bergabung karena kinerja.
JonH
3
Jika Anda harus berhenti bergabung dengan tabel referensi untuk alasan kinerja @JonH Anda perlu membeli server yang lebih besar atau berhenti mencoba mendorong predikat melalui sejumlah besar sub-kueri (saya berasumsi Anda tahu apa yang Anda lakukan). Tabel referensi adalah hal-hal yang harus ada dalam cache Anda dalam beberapa detik setelah memulai DB.
Ben
10

Saya tidak percaya orang belum menyebutkan ini.

Kunci Asing

Dengan menyimpan enum di database Anda, dan menambahkan kunci asing di atas meja yang berisi nilai enum Anda memastikan bahwa tidak ada kode yang pernah memasukkan nilai yang salah untuk kolom itu. Ini membantu integritas data Anda dan merupakan alasan paling jelas IMO Anda harus memiliki tabel untuk enum.

Benjamin Gruenbaum
sumber
Pertanyaannya hanya 5 baris panjang dan jelas menyatakan "Selain alasan yang jelas untuk menegakkan kebenaran". Jadi tidak ada yang menyebutkannya karena OP menyatakan itu jelas dan dia mencari pembenaran lain - PS: Saya setuju dengan Anda, itu alasan yang cukup bagus.
user1007074
6

Saya di kamp yang setuju dengan Anda. Jika Anda menyimpan Gender enum dalam kode Anda dan tblGender dalam basis data Anda, Anda mungkin akan mengalami masalah ketika waktu pemeliharaan. Anda harus mendokumentasikan bahwa kedua entitas ini harus memiliki nilai yang sama dan dengan demikian setiap perubahan yang Anda buat untuk satu Anda juga harus membuat yang lain.

Anda kemudian harus memberikan nilai enum ke prosedur tersimpan Anda seperti:

create stored procedure InsertPerson @name varchar, @gender int
    insert into tblPeople (name, gender)
    values (@name, @gender)

Tetapi pikirkan bagaimana Anda akan melakukan ini jika Anda menyimpan nilai-nilai ini dalam tabel database:

create stored procedure InsertPerson @name varchar, @genderName varchar
    insert into tblPeople (name, gender)
    select @name, fkGender
    from tblGender
    where genderName = @genderName --I hope these are the same

Memang basis data relasional dibangun dengan mempertimbangkan bergabung, tetapi kueri mana yang lebih mudah dibaca?


Berikut ini contoh kueri lainnya:

create stored procedure SpGetGenderCounts
    select count(*) as count, gender
    from tblPeople
    group by gender

Bandingkan dengan ini:

create stored procedure SpGetGenderCounts
    select count(*) as count, genderName
    from tblPeople
    inner join tblGender on pkGender = fkGender
    group by genderName --assuming no two genders have the same name

Berikut ini contoh permintaan lain:

create stored procedure GetAllPeople
    select name, gender
    from tblPeople

Perhatikan bahwa dalam contoh ini, Anda harus mengubah sel gender dalam hasil Anda dari int ke enum. Namun konversi ini mudah. Bandingkan dengan ini:

create stored procedure GetAllPeople
    select name, genderName
    from tblPeople
    inner join tblGender on pkGender = fkGender

Semua pertanyaan ini lebih kecil dan lebih dapat dikelola ketika pergi dengan ide Anda untuk menjaga definisi enum dari database.

pengguna2023861
sumber
1
Bagaimana jika itu bukan gender. Saya pikir kita terlalu terpaku pada gender sebagai bidangnya. Bagaimana jika OP mengatakan "Jadi, misalkan saya memiliki Bug entitas dengan bidang Prioritas" - apakah jawaban Anda akan berubah?
4
@MichaelT Daftar nilai yang mungkin dari "prioritas" adalah bagian dari kode setidaknya pada tingkat yang sama bahwa itu adalah bagian dari data. Anda melihat ikon grafis untuk berbagai prioritas? Anda tidak berharap mereka ditarik dari database? Dan hal-hal seperti itu bisa bertema dan ditata dan masih mewakili kisaran nilai yang sama yang disimpan dalam DB. Anda tidak bisa hanya mengubahnya dalam database; Anda memiliki kode presentasi untuk disinkronkan.
Eugene Ryabtsev
1

Saya akan membuat tabel Jenis Kelamin karena dapat digunakan dalam analisis data. Saya bisa mencari semua Pria atau Wanita di database untuk menghasilkan laporan. Semakin banyak cara Anda melihat data, semakin mudah menemukan informasi tren. Jelas, ini adalah pencacahan yang sangat sederhana, tetapi untuk pencacahan yang rumit (seperti negara di dunia, atau negara bagian), membuatnya lebih mudah untuk menghasilkan laporan khusus.

zackery.fix
sumber
1

Pertama, Anda perlu memutuskan apakah basis data hanya akan digunakan oleh satu aplikasi atau apakah ada potensi beberapa aplikasi untuk menggunakannya. Dalam beberapa kasus database tidak lebih dari format file untuk suatu aplikasi (database SQLite sering dapat digunakan dalam hal ini). Dalam hal ini sedikit menduplikasi definisi enum sebagai tabel sering kali baik dan mungkin lebih masuk akal.

Namun begitu Anda ingin mempertimbangkan kemungkinan memiliki beberapa aplikasi mengakses database, maka tabel untuk enum sangat masuk akal (jawaban lain masuk ke mengapa lebih terinci). Hal lain yang perlu dipertimbangkan adalah Anda atau pengembang lain ingin melihat data basis data mentah. Jika demikian, ini dapat dianggap sebagai penggunaan aplikasi lain (hanya di mana pengukur lab adalah SQL mentah).

Jika Anda memiliki enum yang didefinisikan dalam kode (untuk kode yang lebih bersih dan kompilasi waktu pengecekan) serta tabel dalam database, saya akan merekomendasikan menambahkan tes unit untuk memverifikasi bahwa keduanya sinkron.

Eric Johnson
sumber
1

Ketika Anda memiliki kode enumerasi yang digunakan untuk mendorong logika bisnis dalam kode Anda masih harus membuat tabel untuk mewakili data dalam DB karena berbagai alasan yang dijelaskan di atas / di bawah. Berikut adalah beberapa tips untuk memastikan bahwa nilai DB Anda tetap sinkron dengan nilai kode:

  1. Jangan jadikan bidang ID pada tabel sebagai kolom Identitas. Sertakan ID dan Deskripsi sebagai bidang.

  2. Lakukan sesuatu yang berbeda dalam tabel yang membantu pengembang tahu bahwa nilai-nilai semi-statis / terikat pada penghitungan kode. Di semua tabel pencarian lainnya (biasanya di mana nilai dapat ditambahkan oleh pengguna) Saya biasanya memiliki LastChangedDateTime dan LastChangedBy, tetapi tidak memilikinya pada tabel terkait enum membantu saya mengingat bahwa mereka hanya dapat diubah oleh pengembang. Dokumentasikan ini.

  3. Buat kode verifikasi yang memeriksa untuk melihat bahwa setiap nilai dalam enumerasi berada di tabel terkait, dan hanya nilai-nilai itu yang ada di tabel terkait. Jika Anda memiliki aplikasi otomatis "tes kesehatan" yang menjalankan post-build, lakukanlah di sana. Jika tidak, buat kode berjalan secara otomatis saat startup aplikasi setiap kali aplikasi berjalan di IDE.

  4. Buat produksi menghasilkan skrip SQL yang melakukan hal yang sama, tetapi dari dalam DB. Jika dibuat dengan benar mereka juga akan membantu dengan migrasi lingkungan.

Paul Schirf
sumber
0

Tergantung juga pada siapa yang mengakses data. Jika Anda hanya memiliki satu aplikasi yang mungkin baik-baik saja. Jika Anda menambahkan data warehouse atau sistem pelaporan. Mereka perlu tahu apa artinya kode itu, apa versi kode yang dapat digunakan kembali manusia.

Biasanya, tabel tipe tidak akan diduplikasi sebagai enum dalam kode. Anda bisa memuat tabel tipe dalam daftar yang di-cache.

Class GenderList

   Public Shared Property UnfilteredList
   Public Shared Property Male = GetItem("M")
   Public Shared Property Female = GetItem("F")

End Class

Seringkali, ketik datang dan pergi. Anda memerlukan tanggal kapan tipe baru ditambahkan. Ketahui kapan jenis tertentu dihapus. Tampilkan hanya saat dibutuhkan. Bagaimana jika klien ingin "transgender" sebagai jenis kelamin tetapi klien lain tidak? Semua informasi ini paling baik disimpan dalam database.

the_lotus
sumber