Menggunakan tabel konfigurasi Single Row dalam database SQL Server. Ide buruk?

145

Dalam mengembangkan aplikasi keranjang belanja, saya menemukan bahwa saya perlu menyimpan pengaturan dan konfigurasi berdasarkan preferensi dan persyaratan administrator. Informasi ini dapat berupa apa saja dari informasi perusahaan, ID akun pengiriman, kunci API PayPal, preferensi pemberitahuan, dll.

Tampaknya sangat tidak tepat untuk membuat tabel untuk menyimpan satu baris dalam sistem basis data relasional.

Apa cara yang tepat untuk menyimpan informasi ini?

Catatan: DBMS saya adalah SQL Server 2008 dan lapisan pemrograman diimplementasikan dengan ASP.NET (dalam C #).

David Murdoch
sumber

Jawaban:

189

Saya telah melakukan dua cara ini di masa lalu - tabel baris tunggal dan tabel pasangan kunci / nilai - dan ada positif dan negatif untuk setiap pendekatan.

Baris tunggal

  • positif: nilai disimpan dalam tipe yang benar
  • positif: lebih mudah untuk berurusan dengan kode (karena hal di atas)
  • positif: nilai default dapat diberikan untuk setiap pengaturan secara individual
  • negatif: perubahan skema diperlukan untuk menambahkan pengaturan baru
  • negatif: tabel bisa menjadi sangat luas jika ada banyak pengaturan

Pasangan Kunci / Nilai

  • positif: menambahkan pengaturan baru tidak memerlukan perubahan skema
  • positif: skema tabel sempit, dengan baris tambahan digunakan untuk pengaturan baru
  • negatif: setiap pengaturan memiliki nilai default yang sama (nol / kosong?)
  • negatif: semuanya harus disimpan sebagai string (mis. nvarchar)
  • negatif: ketika berhadapan dengan pengaturan dalam kode, Anda harus tahu jenis pengaturan apa dan melemparkannya

Opsi baris tunggal sejauh ini merupakan yang termudah untuk dikerjakan. Ini karena Anda dapat menyimpan setiap pengaturan dalam tipe yang benar dalam database dan tidak harus menyimpan jenis pengaturan serta kunci pencariannya dalam kode.

Satu hal yang saya khawatirkan dengan menggunakan pendekatan ini adalah memiliki beberapa baris dalam tabel pengaturan baris tunggal "khusus". Saya mengatasinya dengan (dalam SQL Server):

  • menambahkan kolom bit baru dengan nilai default 0
  • membuat batasan pemeriksaan untuk memastikan bahwa kolom ini memiliki nilai 0
  • membuat batasan unik pada kolom bit

Ini berarti bahwa hanya satu baris yang bisa ada dalam tabel karena kolom bit harus memiliki nilai 0, tetapi hanya ada satu baris dengan nilai itu karena kendala unik.

adrianbank
sumber
5
Kami melakukan hal satu baris dalam aplikasi LOB kami. Nilai-nilainya semua jenis yang benar, yang membuatnya menggunakannya dalam aplikasi lebih sederhana. Skema kami diversi versi bersama dengan aplikasi, jadi perubahan pada pengaturan konfigurasi dikelola sama seperti revisi aplikasi apa pun.
DaveE
17
Satu baris positif: Dapat membuat FK didefinisikan pada beberapa kolom!
wqw
8
Anda selalu dapat melakukan pasangan kunci / nilai dengan pengenal tipe untuk menentukan kolom mana yang memiliki nilai dalam tipe nilainya. Ini memberi Anda yang terbaik dari kedua dunia dan Anda dapat menggunakan proc yang disimpan untuk mendapatkan nilai saat Anda membutuhkannya.
Middletone
19
Satu hal yang benar-benar dapat merusak hari Anda setelah menerapkan solusi baris tunggal adalah ketika Anda kemudian ditugasi "mari juga melacak kapan terakhir kali setiap nilai diubah dan siapa yang mengubahnya ...."
Dave Mateer
6
Keuntungan lain dari solusi baris tunggal, yang saya temukan dalam satu kasus: Saya memiliki aplikasi yang dibangun untuk satu klien, dengan tabel baris tunggal untuk "pengaturan". Saya kemudian mendapatkan dua klien lain yang ingin menggunakan aplikasi yang sama, tetapi menginginkan pengaturan yang berbeda: yang harus saya lakukan adalah menambahkan PK "client_id" ke meja untuk mempertahankan satu set pengaturan terpisah untuk setiap klien. (Ini adalah ketika Anda menyadari bahwa "pengaturan" ini benar-benar hanya atribut untuk entitas tingkat yang lebih tinggi yang belum Anda modelkan.)
Jeffrey Kemp
10

Anda harus membuat tabel dengan kolom untuk jenis informasi dan nilai informasi (setidaknya). Dengan cara ini Anda menghindari membuat kolom baru setiap kali informasi baru ditambahkan.

Otávio Décio
sumber
1
Sederhana dan rapi. Hanya bekerja dengan daftar pasangan nilai kunci dari sana. Anda mungkin ingin berpikir tentang nilai default sedikit, tergantung pada konteks penggunaan ...
Paul Kohler
4
Mengapa masalah membuat kolom baru? Saya tahu ada situasi di mana pengembang harus menghindarinya karena masalah politik dengan memperbarui skema SQL, tetapi tidak disebutkan dalam pertanyaan itu.
finnw
6

Satu baris akan berfungsi dengan baik; itu bahkan akan memiliki tipe yang kuat:

show_borders    bit
admin_name      varchar(50)
max_users       int

Salah satu kelemahannya adalah membutuhkan perubahan skema ( alter table) untuk menambahkan pengaturan baru. Salah satu alternatif adalah normalisasi, di mana Anda berakhir dengan tabel seperti:

pref_name       varchar(50) primary key
pref_value      varchar(50) 

Ini memiliki tipe yang lemah (semuanya adalah varchar), tetapi menambahkan pengaturan baru hanya menambahkan baris, sesuatu yang dapat Anda lakukan hanya dengan akses menulis basis data.

Andomar
sumber
4

Secara pribadi, saya akan menyimpannya dalam satu baris jika itu yang berhasil. Berlebihan untuk menyimpannya dalam tabel SQL? mungkin, tetapi tidak ada salahnya melakukannya.

EJ Brennan
sumber
4

Seperti yang Anda tebak, dan kecuali untuk situasi yang paling sederhana, menempatkan semua parameter konfigurasi dalam satu baris memiliki banyak kelemahan. Itu ide yang buruk ...

Cara mudah untuk menyimpan konfigurasi dan / atau jenis informasi preferensi pengguna adalah dalam XML . Banyak DBMS mendukung tipe data XML. Sintaks XML memungkinkan Anda mengeluarkan "bahasa" dan struktur yang menjelaskan konfigurasi saat konfigurasi ini berkembang. Salah satu keunggulan XML adalah dukungan implisitnya untuk struktur hierarkis, yang memungkinkan misalnya untuk menyimpan daftar kecil parameter konfigurasi tanpa harus menamai ini dengan akhiran bernomor. Kelemahan yang mungkin dari format XML adalah bahwa pencarian dan umumnya memodifikasi data ini tidak semudah pendekatan lainnya (tidak ada yang rumit, tetapi tidak sesederhana / alami)

Jika Anda ingin tetap lebih dekat dengan model relasional , model Entity-Attribute-Value mungkin yang Anda butuhkan, di mana nilai individual disimpan dalam tabel yang biasanya terlihat seperti:

EntityId     (foreign key to the "owner" of this attribute)
AttributeId  (foreign key to the "metadata" table where the attribute is defined)
StringValue  (it is often convenient to have different columns of different types
IntValue      allowing to store the various attributes in a format that befits 
              them)

Dimana AttributeId adalah kunci asing ke tabel di mana setiap atribut yang mungkin ("parameter konfigurasi" dalam kasus Anda) didefinisikan, dengan mengatakan

AttributeId  (Primary Key)
Name
AttributeType     (some code  S = string, I = Int etc.)
Required          (some boolean indicating that this is required)
Some_other_fields   (for example to define in which order these attributes get displayed etc...)

Akhirnya, EntityId memungkinkan Anda mengidentifikasi beberapa entitas yang "memiliki" berbagai atribut ini. Dalam kasus Anda itu bisa menjadi UserID atau bahkan hanya implisit jika Anda hanya memiliki satu konfigurasi untuk dikelola.

Selain memungkinkan daftar parameter konfigurasi yang mungkin untuk tumbuh sebagai aplikasi berkembang, model EAV menempatkan "meta data", yaitu data yang berkaitan dengan Atribut itu sendiri, dalam data, sehingga menghindari semua pengodean nama kolom yang umum dilihat. ketika parameter konfigurasi disimpan dalam satu baris.

mjv
sumber
3
Kedengarannya seperti berlebihan untuk sebagian besar penggunaan tabel konfigurasi.
JerryOL
Saya pikir ide umum di balik pendekatan ini sangat bagus. Tapi mengapa XML? Pilih saja format pertukaran data sederhana seperti JSON atau YAML dan Anda bisa mendapatkan keuntungan dari kedua variasi lainnya.
schlamar
1
EAV bersifat relasional tetapi tidak dinormalisasi. Memang ada kasus penggunaan untuk itu (misalnya sistem ORM tampaknya menyukai mereka), tetapi argumen bahwa meta data dalam database untuk EAV bukan alasan yang meyakinkan untuk menggunakannya. Semua RDBMS mengandung data meta dalam tabel sistem yang dapat Anda temukan, sehingga tabel baris tunggal juga memiliki metadata dalam database. Nama kolom hard-kode juga bukan masalah. Jika Anda menggunakan kunci untuk entitas dan atribut maka Anda punya tabel pencarian kode keras di tempat lain yang mendefinisikannya (atau lebih buruk itu ada di lapisan presentasi Anda).
Davos
3

Anda tentu tidak perlu mengubah skema Anda saat menambahkan parameter konfigurasi baru dalam pendekatan normal, tetapi Anda mungkin masih mengubah kode Anda untuk memproses nilai baru.

Menambahkan "alter table" ke penyebaran Anda sepertinya tidak terlalu penting untuk kesederhanaan dan keamanan jenis pendekatan baris tunggal.

Dave Mikesell
sumber
2

Pasangan Kunci dan Nilai mirip dengan .Net App.Config yang dapat menyimpan pengaturan konfigurasi.

Jadi ketika Anda ingin mengambil nilai yang bisa Anda lakukan:

SELECT value FROM configurationTable
WHERE ApplicationGroup = 'myappgroup'
AND keyDescription = 'myKey';
rizalp1
sumber
1

Cara umum untuk melakukan ini adalah memiliki tabel "properti" yang mirip dengan file properti. Di sini Anda dapat menyimpan semua konstanta aplikasi Anda, atau hal-hal yang tidak begitu konstan yang hanya perlu Anda miliki.

Anda kemudian dapat mengambil info dari tabel ini sesuai kebutuhan. Demikian juga, ketika Anda menemukan Anda memiliki beberapa pengaturan lain untuk disimpan, Anda dapat menambahkannya. Ini adalah sebuah contoh:

property_entry_table

[id, scope, refId, propertyName, propertyValue, propertyType] 
1, 0, 1, "COMPANY_INFO", "Acme Tools", "ADMIN"  
2, 0, 1, "SHIPPING_ID", "12333484", "ADMIN"  
3, 0, 1, "PAYPAL_KEY", "2143123412341", "ADMIN"   
4, 0, 1, "PAYPAL_KEY", "123412341234123", "ADMIN"  
5, 0, 1, "NOTIF_PREF", "ON", "ADMIN"  
6, 0, 2, "NOTIF_PREF", "OFF", "ADMIN"   

Dengan cara ini Anda dapat menyimpan data yang Anda miliki, dan data yang akan Anda miliki tahun depan dan belum tahu tentangnya :).

Dalam contoh ini, ruang lingkup dan refId Anda dapat digunakan untuk apa pun yang Anda inginkan di bagian belakang. Jadi jika propertyType "ADMIN" memiliki cakupan 0 refId 2, Anda tahu preferensi itu.

Jenis properti ada di tangan ketika, suatu hari, Anda perlu menyimpan info non-admin di sini juga.

Perhatikan bahwa Anda tidak boleh menyimpan data keranjang dengan cara ini, atau mencari hal tersebut. Namun jika datanya spesifik Sistem , maka Anda tentu dapat menggunakan metode ini.

Misalnya: Jika Anda ingin menyimpan DATABASE_VERSION Anda, Anda akan menggunakan tabel seperti ini. Dengan begitu, ketika Anda perlu memperbarui aplikasi, Anda dapat memeriksa tabel properti untuk melihat versi perangkat lunak apa yang dimiliki klien.

Intinya adalah Anda tidak ingin menggunakan ini untuk hal-hal yang berkaitan dengan kereta. Membuat Anda logika bisnis dalam tabel relasional yang didefinisikan dengan baik. Tabel properti hanya untuk info sistem.

Stephano
sumber
@ finnw Saya setuju sepenuhnya bahwa metode ini tidak boleh digunakan untuk pencarian, terutama ketika ada banyak jenis pencarian yang berbeda. Mungkin saya salah mengerti pertanyaan itu. Kedengarannya dia membutuhkan meja untuk konstanta dan properti sistem. Dalam hal ini, mengapa ada 10 tabel berbeda?
Stephano
catatan: katanya "simpan pengaturan dan konfigurasi", bukan "Saya perlu menyimpan data kereta relasional"
Stephano
Keberatan saya untuk ini adalah bahwa Anda melewati pengetikan SQL dan mekanisme kendala lainnya untuk menghindari memperbarui skema SQL ketika Anda menambahkan atribut baru. Seperti yang Anda katakan "data yang akan Anda miliki tahun depan dan belum tahu tentangnya." Ya, Anda akan memiliki data baru tahun depan, tetapi apa yang akan menghentikan Anda membuat kolom SQL baru (diketik), PERIKSA dan mungkin kendala ASING KUNCI untuk itu pada saat itu ditambahkan?
finnw
Insting pertama saya adalah menambahkan data ini ke file datar. Dan Anda benar, proses ini menggunakan tabel sebagai gantinya memang akan menghindari mekanisme kendala dari DBMS. Namun, saya akan mengatakan bahwa jika Anda berusaha terlalu keras untuk mengikuti teknik basis data yang tepat, Anda kehilangan intinya. Lihatlah jawaban pertama; memberikan suara tertinggi pada SO: stackoverflow.com/questions/406760/…
Stephano
2
Saya akan memasangkan pasangan nilai kunci, membuang semuanya ke dalam kamus saat memulai dan Anda disortir.
Paul Creasey
0

Saya tidak yakin satu baris adalah implementasi terbaik untuk konfigurasi. Anda mungkin lebih baik memiliki satu baris per item konfigurasi dengan dua kolom (configName, configValue), meskipun ini membutuhkan casting semua nilai Anda ke string dan kembali.

Apapun, tidak ada salahnya menggunakan satu baris untuk konfigurasi global. Opsi lain untuk menyimpannya di DB (variabel global) lebih buruk. Anda bisa mengendalikannya dengan menyisipkan baris konfigurasi pertama Anda, kemudian menonaktifkan sisipan di atas meja untuk mencegah beberapa baris.

yg berkenaan dgn bintang
sumber
0

Anda dapat melakukan Pasangan Kunci / Nilai tanpa konversi dengan menambahkan kolom untuk setiap jenis utama dan satu kolom yang memberi tahu Anda kolom tempat data berada.

Jadi meja Anda akan terlihat seperti:

id, column_num, property_name, intValue, floatValue, charValue, dateValue
1, 1, weeks, 51, , ,
2, 2, pi, , 3.14159, , 
3, 4, FiscYearEnd, , , , 1/31/2015
4, 3, CompanyName, , , ACME, 

Ini menggunakan sedikit lebih banyak ruang tetapi paling banyak Anda menggunakan beberapa lusin atribut. Anda dapat menggunakan pernyataan kasus dari nilai column_num untuk menarik / bergabung dengan bidang kanan.

spintool
sumber
0

Maaf saya datang suka, ya nanti. Tetapi bagaimanapun juga, apa yang saya lakukan adalah sederhana dan efektif. Saya cukup membuat tabel dengan tiga () kolom:

ID - int (11)

name - varchar (64)

nilai - teks

Apa yang saya lakukan sebelum membuat kolom konfigurasi baru, memperbaruinya atau membaca adalah membuat cerita bersambung "nilai"! Dengan cara ini saya yakin akan tipenya (Ya, php is :))

Misalnya:

b: 0; adalah untuk B OOLEAN ( salah )

b: 1; adalah untuk B OOLEAN ( benar )

i: 1988; adalah untuk saya NT

s: 5: "Kader"; adalah untuk S TRING dengan panjang 5 karakter

Saya harap ini membantu :)

Kader Bouyakoub
sumber
1
Mengapa tidak membuat kolom baru untuk jenis itu? i:1988Sepertinya Anda sedang mencoba untuk menciutkan dua informasi menjadi satu kolom.
maksymiuk
@maksymiuk Hanya karena sekali unserialized Anda mendapatkan tipe yang tepat daripada menggunakan loop setelah (jika atau beralih) ... dll
Kader Bouyakoub
tidak perlu untuk loop atau switch atau apa pun, itu benar-benar akan menghapus langkah harus mengurai informasi dari setiap baris, sedangkan, jika Anda memiliki kolom tambahan untuk tipe, informasi tipe sudah tersedia untuk komponen yang menarik informasi tanpa harus melakukan langkah lebih lanjut dari sekedar permintaan awal
maksymiuk
Maksud Anda dengan melakukan sesuatu seperti echo (int) $varuntuk integer dan lainnya untuk tipe lain?
Kader Bouyakoub
0

Memiliki kolom kunci sebagai varchar dan kolom nilai sebagai JSON. 1adalah numerik sedangkan "1"string. truedan falsekeduanya boolean. Anda dapat memiliki objek juga.

kzh
sumber