Data konfigurasi: tabel baris tunggal vs tabel pasangan nama-nilai

64

Katakanlah Anda menulis aplikasi yang dapat dikonfigurasi oleh pengguna. Untuk menyimpan "data konfigurasi" ini ke dalam basis data, dua pola biasanya digunakan.

  1. The meja tunggal-baris

      CompanyName  |  StartFullScreen  |  RefreshSeconds  |  ...
    ---------------+-------------------+------------------+--------
      ACME Inc.    |        true       |       20         |  ...
    
  2. The nama-nilai-pair meja

      ConfigOption   |   Value
    -----------------+-------------
     CompanyName     | ACME Inc.
     StartFullScreen | true (or 1, or Y, ...)
     RefreshSeconds  | 20
     ...             | ...
    

Saya telah melihat kedua opsi di alam liar, dan keduanya memiliki kelebihan dan kekurangan yang jelas, misalnya:

  • Tabel baris tunggal membatasi jumlah opsi konfigurasi yang dapat Anda miliki (karena jumlah kolom dalam satu baris biasanya terbatas). Setiap opsi konfigurasi tambahan memerlukan perubahan skema DB.
  • Dalam tabel pasangan nama-nilai semuanya "diketik secara ketat" (Anda harus menyandikan / mendekode parameter Boolean / Tanggal / dll.)
  • (masih banyak lagi)

Apakah ada beberapa konsensus dalam komunitas pembangunan tentang opsi mana yang lebih disukai?

Heinzi
sumber
2
Tidak ada alasan pendekatan 'vertikal' tidak memiliki tipe data yang berbeda. Tambahkan kolom int, float, dan teks per baris. Simpan / muat nilai darinya menggunakan fungsi tipe-spesifik, seperti 'SaveConfigInt (' field ', n)'
GrandmasterB
4
Ada pertanyaan StackOverflow luar biasa yang menanyakan hal ini, dan jawaban teratas memberikan pro dan kontra untuk kedua pendekatan. stackoverflow.com/questions/2300356/…
Kevin - Reinstate Monica
1
Pendekatan 3: Kolom Tunggal / Baris Tunggal dengan format pertukaran data sederhana seperti JSON atau YAML. Menggabungkan keunggulan dari kedua pendekatan.
schlamar
bagaimana dengan menggunakan tabel baris tunggal dengan data kompleks yang mengandung xml / json seperti <config> <CompanyName> ACME Inc. </CompanyName> <StartFullScreen> true </StartFullScreen> benar </StartFullScreen>20<RefreshSeconds></RefreshSeconds> </config> dan memvalidasi objek di lapisan bisnis?
John
1
@ John: Ide bagus, jika diperlukan struktur hierarkis. Jika tidak, itu hanya opsi 2 dengan kompleksitas yang ditambahkan.
Heinzi

Jawaban:

15

Saya pribadi lebih suka tabel baris tunggal untuk banyak hal. Memang benar bahwa itu kurang fleksibel, kecuali jika Anda mengharapkan perilaku dinamis, itu sangat dapat diterima untuk menambahkan kolom tambahan nanti jika Anda perlu. Di satu sisi, itu setara dengan menggunakan kamus / peta untuk menahan pasangan nama-nilai vs memiliki anggota kelas saat pemrograman. Memang, ini bukan metafora yang sempurna, tetapi banyak keuntungan dan kerugiannya paralel ketika Anda memikirkannya.

Jadi apakah Anda akan menggunakan kamus / peta di atas anggota kelas? Mungkin tidak kecuali Anda memiliki alasan untuk berpikir bahwa jumlah data yang akan diwakili sepenuhnya dapat disesuaikan, seperti memiliki tabel pasangan nama-nilai.

Neil
sumber
Bagaimana jika data yang akan disimpan ditentukan oleh pengguna? yaitu memikirkan UI di mana pengguna dapat membuat "bidang" dengan menentukan label bidang, jenis data yang akan dipegang, dll. Itu berarti mengeksekusi pernyataan DDL dari kode. Apakah Anda masih menggunakan opsi 1?
devanalyst
1
@devanalyst Tidak, jika data dapat berubah dari komponen ke komponen, maka tidak masuk akal untuk mencoba membuat tabel statis untuk mewakilinya. Dalam hal ini akan lebih baik menggunakan opsi kedua.
Neil
12

Saya biasanya pergi dengan opsi 2 TAPI saya punya beberapa kolom untuk menegakkan tipe data

ConfigOption   |   textValue    |   DateValue   |   NumericValue

Opsi 1 Memiliki Manfaat tambahan yang Anda dapat dengan mudah "Swap" seluruh Konfigurasi dengan menambahkan ActiveKolom.

Orang bodoh
sumber
Jika Anda mengizinkan konfigurasi dinonaktifkan (untuk opsi 1), paling tidak buatlah activatedOntimestamp, jadi Anda bisa tahu kapan itu diaktifkan. Dan jika Anda pergi dengan opsi 2 ... apa yang terjadi jika akhirnya menyimpan nilai dalam beberapa kolom (atau itu oracle, di mana (tampaknya) nol dan string kosong adalah setara)?
Clockwork-Muse
1
@ X-Zero, menyimpan Multiple Configs biasanya dilakukan untuk tujuan pengujian, tetapi cap waktu tidak dapat rusak. Config Maintenance, panggilan untuk mendapatkan nilai akan tahu kolom apa yang harus diperiksa, jika Anda benar-benar ingin, Anda bisa menambahkan kolom untuk tipe data .. Tapi saya pikir itu lebih dari membunuh ...
Morons
5
skema EATV (Entity-Attribute-Type-Value) memecah bentuk normal ketiga; kolom Type hanya secara tidak langsung terkait dengan kunci utama tabel, melalui kolom Value yang dijelaskan kolom Type. Selain itu, penyimpanan tipe dinamis dan instantiasi tidak banyak menyelesaikan masalah; Jika metode GetConfigValue () dapat mengembalikan tipe apa pun, ia harus mengembalikan Object (atau diberikan tipe yang diharapkan) yang masih harus dievaluasi saat runtime.
KeithS
5
Setiap opsi 1 telah diimplementasikan dalam perangkat lunak yang saya lihat, itu harus dikonversi ke opsi 2. Opsi 2 lebih mudah untuk mempertahankan dari waktu ke waktu, hanya butuh sentuhan lebih banyak waktu untuk menerapkan dengan benar pertama kali. Opsi 1 cepat dan mudah diimplementasikan tetapi pemeliharaan dari waktu ke waktu sangat mengerikan kecuali perangkat lunak Anda kecil tanpa peluang tumbuh.
Jimmy Hoffa
8

Bagi saya, apakah Anda menggunakan satu baris atau EAV tergantung pada bagaimana Anda ingin mengkonsumsinya.

Kekuatan EAV adalah bahwa data baru dapat ditambahkan tanpa perubahan struktur. Ini berarti bahwa jika Anda menginginkan nilai konfigurasi baru, Anda cukup menambahkannya ke tabel dan menariknya ke tempat yang Anda inginkan dalam kode, dan Anda tidak perlu menambahkan bidang baru ke domain, skema, pemetaan, permintaan DAL , dll.

Kekurangannya adalah bahwa ia hanya memiliki struktur paling sederhana, yang mengharuskan Anda untuk berurusan dengan data secara pesimistis. Setiap penggunaan nilai konfigurasi apa pun harus mengharapkan nilai tidak ada, atau tidak dalam format yang tepat, dan berperilaku sesuai ketika tidak. Nilai konfigurasi mungkin tidak dapat diuraikan menjadi ganda, atau int, atau char. Mungkin nol. mungkin tidak ada baris untuk nilai sama sekali. Cara-cara di sekitar ini biasanya memerlukan satu nilai "default" yang valid untuk ada untuk semua nilai konfigurasi dari jenis kode tertentu ( sangat jarang; lebih sering nilai default sama bermasalah untuk mengkonsumsi kode seperti tidak ada sama sekali), atau untuk menyimpan kamus hardcoded dari nilai-nilai default (yang harus berubah setiap kali kolom baru ditambahkan, membuat keunggulan utama penyimpanan EAV cukup diperdebatkan).

Satu baris lebar adalah kebalikannya. Anda memetakannya ke satu instance objek Konfigurasi dengan bidang / properti untuk setiap nilai konfigurasi yang ada. Anda tahu persis apa tipe nilai-nilai itu harus pada waktu kompilasi, dan Anda "gagal cepat" di DAL jika kolom konfigurasi tidak ada atau tidak memiliki nilai tipe yang tepat, memberi Anda satu tempat untuk menangkap pengecualian berdasarkan pada masalah pengambilan konfigurasi / hidrasi.

Kerugian utama adalah bahwa perubahan struktural diperlukan untuk setiap nilai baru; kolom DB baru, kolom baru di DAL (baik pemetaan atau kueri SQL / SP), kolom domain baru, semua yang diperlukan untuk menguji penggunaan dengan benar.

Situasi yang tepat untuk menggunakan salah satu dari ini adalah situasi di mana kerugian dikurangi. Bagi saya, sebagian besar situasi untuk pengkodean konfigurasi telah menyerukan implementasi baris tunggal. Ini terutama karena jika Anda memperkenalkan nilai konfigurasi yang sama sekali baru yang mengatur perilaku beberapa bagian dari program Anda, Anda harus mengubah kode untuk menggunakan nilai konfigurasi baru; mengapa tidak mampir ke objek konfigurasi dan menambahkan nilai yang akan digunakan?

Singkatnya, skema EAV untuk menyimpan konfigurasi benar-benar tidak menyelesaikan masalah yang ingin diselesaikan, dan sebagian besar solusi untuk masalah yang dihadapinya melanggar KERING.

KeithS
sumber
3

Khusus untuk nilai konfigurasi, saya akan mengatakan - pergi dengan satu baris. Kecuali jika Anda saat ini sedang menjalani pengembangan, seberapa sering kolom itu akan berubah?

Mungkin lebih baik untuk mengamankan tipe data dari nilai , daripada kode untuk ekstensibilitas yang kemungkinan besar tidak Anda miliki di waktu henti antara rilis besar (r). Selain itu, menambahkan atau menghapus satu kolom hanyalah tentang migrasi termudah yang ada. Saya tidak melihat sakit kepala ketika membuat opsi konfigurasi baru.

Selain itu, Anda mengatakan "pengguna" dapat mengonfigurasi opsi ini, tanpa memberi batasan. Apakah itu konfigurasi per pengguna? Jika demikian, saya akan berpendapat lebih kuat lagi bahwa opsi konfigurasi harus ada di kolom - satu baris per pengguna. Ini akan menghemat banyak sakit kepala perawatan nanti.

Izkata
sumber
2

Jika klien Anda dapat memproses fragmen JSON (yang bukan hanya array dan kamus, tetapi juga string, angka, boolean, nilai nol) maka Anda dapat memiliki tabel multi-baris dengan nama opsi dan nilai string yang berisi JSON. Itu memungkinkan Anda untuk juga menyimpan nilai terstruktur, dan kode untuk memproses ini seharusnya sudah ada di sana.

Jika klien Anda tidak dapat memproses fragmen JSON, dapatkan klien baru.

gnasher729
sumber
1

Pro baris tunggal: Didefinisikan dengan baik. Cons: Mengubah konfigurasi bisa sangat menyebalkan. Migrasi DB dll.

Entity-Value Pro: Sangat fleksibel, mendukung pengembangan konfigurasi Anda. Kekurangan: Integritas referensial? Pemeriksaan lebih lanjut dalam kode Anda untuk melihat apakah properti itu ada sebelum Anda dapat melakukan apa pun di sana.

Saya akan mengambil pendekatan 2 yang didukung oleh db non-relasional seperti Mongo. Jika ada sesuatu yang bisa Anda yakini, perubahannya.

JVXR
sumber
1

Gunakan keduanya!

Urutkan opsi apa yang dapat memiliki banyak instance, dan opsi apa yang generik.

Tabel baris tunggal (konfigurasi)

  id  |  company_name  |  start_fullscreen  |  refresh_seconds  |  ...
------+----------------+--------------------+-------------------+-------
  4   |  ACME Inc.     |  true              |  20               |  ...

Tabel pasangan nama-nilai (opsi)

  name             |  value          | update_time  
-------------------+-----------------+--------------
  generic_option_1 |  Option 1 Value | timestamp    
  generic_option_2 |  Option 2 Value | timestamp    
  generic_option_3 |  Option 3 Value | timestamp    
  configuration    |  4              | timestamp    
  ...              |  ...            | ...          

Saya pikir ini lebih fleksibel.

Andrew Luca
sumber