Pertanyaan ini seputar bagaimana saya harus mendesain database, bisa berupa database relasional / nosql, tergantung pada apa yang akan menjadi solusi yang lebih baik
Diberi persyaratan di mana Anda harus membuat sistem yang akan melibatkan basis data untuk melacak "Perusahaan" dan "Pengguna". Satu pengguna selalu hanya milik satu perusahaan
- Seorang pengguna hanya dapat menjadi bagian dari satu perusahaan
- Perusahaan dapat memiliki banyak pengguna
Desain untuk tabel "Perusahaan" cukup mudah. Perusahaan akan memiliki atribut / kolom berikut: (mari kita tetap sederhana)
ID, COMPANY_NAME, CREATED_ON
Skenario pertama
Sederhana & lurus ke depan, semua pengguna memiliki atribut yang sama, jadi ini dapat dengan mudah dilakukan dalam gaya relasional, tabel pengguna:
ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CREATED_ON
Skenario kedua
Apa yang terjadi jika perusahaan yang berbeda ingin menyimpan atribut profil yang berbeda untuk pengguna mereka. Setiap perusahaan akan memiliki seperangkat atribut yang ditentukan yang akan berlaku untuk semua pengguna perusahaan itu.
Sebagai contoh:
- Perusahaan A ingin menyimpan: LIKE_MOVIE (boolean), LIKE_MUSIC (boolean)
- Perusahaan B ingin menyimpan: FAV_CUISINE (String)
- Perusahaan C ingin menyimpan: OWN_DOG (boolean), DOG_COUNT (int)
Pendekatan 1
cara brute force adalah memiliki skema tunggal untuk pengguna dan membiarkan mereka memiliki nol ketika mereka bukan milik perusahaan:
ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, LIKE_MOVIE, LIKE_MUSIC, FAV_CUISINE, OWN_DOG, DOG_COUNT, CREATED_ON
Yang agak jahat karena Anda akan berakhir dengan banyak NULLS dan baris pengguna yang memiliki kolom yang tidak relevan dengan mereka (mis. Semua pengguna milik Perusahaan A memiliki nilai NULL untuk FAV_CUISINE, OWN_DOG, DOG_COUNT)
Pendekatan 2
pendekatan kedua, adalah memiliki "bidang bentuk bebas":
ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CUSTOM_1, CUSTOM_2, CUSTOM_3, CREATED_ON
Yang tidak menyenangkan karena Anda sendiri tidak tahu bidang khusus apa, tipe data tidak akan mencerminkan nilai yang disimpan (mis. Kami akan menyimpan nilai int sebagai VARCHAR).
Pendekatan 3
Saya telah melihat ke dalam bidang JSON PostgreSQL, dalam hal ini Anda akan memiliki:
ID, COMPANY_ID, FIRST_NAME, LAST_NAME, EMAIL, CUSTOM_PROFILE_JSON, CREATED_ON
Dalam hal ini, bagaimana Anda bisa menerapkan skema yang berbeda untuk pengguna? Seorang pengguna dengan Perusahaan A akan memiliki skema yang terlihat seperti
{"LIKE_MOVIE":"boolean", "LIKE_MUSIC": "boolean"}
Sementara pengguna dengan Perusahaan C akan memiliki skema berbeda:
{"OWN_DOG ":"boolean", "DOG_COUNT": "int"}
Bagaimana saya mengatasi masalah ini? Bagaimana saya bisa mendesain database dengan benar untuk memungkinkan skema fleksibel ini untuk satu "objek" (Pengguna) berdasarkan hubungan yang mereka miliki (Perusahaan)?
solusi relasional? solusi nosql?
Sunting: Saya juga memikirkan tabel "CUSTOM_PROFILE" yang pada dasarnya akan menyimpan atribut pengguna dalam baris daripada kolom.
Ada 2 masalah dengan pendekatan ini:
1) Data tumbuh per pengguna tumbuh sebagai baris daripada kolom - dan ini berarti untuk mendapatkan gambaran lengkap dari pengguna, banyak gabungan yang harus dilakukan, beberapa bergabung ke tabel "profil khusus" pada atribut khusus yang berbeda
2) Nilai data selalu disimpan sebagai VARCHAR untuk menjadi generik, bahkan jika kita tahu data itu seharusnya bilangan bulat atau boolean dll
sumber
Jawaban:
Harap pertimbangkan ini sebagai alternatif. Dua contoh sebelumnya akan mengharuskan Anda membuat perubahan pada skema saat ruang lingkup aplikasi bertambah selain solusi "custom_column" sulit untuk diperluas dan dipelihara. Akhirnya, Anda akan berakhir dengan Custom_510 dan bayangkan betapa buruknya tabel ini.
Pertama, mari kita gunakan skema Perusahaan Anda.
Selanjutnya kami juga akan menggunakan skema Pengguna Anda untuk atribut tingkat atas yang diperlukan yang akan digunakan / dibagikan oleh semua perusahaan.
Selanjutnya kita membuat tabel di mana kita akan mendefinisikan atribut dinamis kita yang spesifik untuk setiap atribut pengguna khusus perusahaan. Jadi di sini nilai contoh kolom Atribut adalah "LikeMusic":
Selanjutnya kita mendefinisikan tabel UserAttributes yang akan menyimpan nilai atribut pengguna
Ini dapat dimodifikasi dengan berbagai cara untuk menjadi lebih baik untuk kinerja. Anda bisa menggunakan beberapa tabel untuk UserAttributes yang membuat masing-masing spesifik untuk tipe data yang disimpan di Value atau biarkan saja sebagai VarChar dan bekerja dengannya sebagai store nilai kunci.
Anda juga mungkin ingin memindahkan CompanyId dari tabel UserAttributeDefiniton dan ke tabel referensi silang untuk pemeriksaan selanjutnya.
sumber
Gunakan database NoSQL. Akan ada dokumen perusahaan dan pengguna. Pengguna akan memiliki bagian dari skema mereka yang dibuat secara dinamis berdasarkan pada templat pengguna (teks untuk menunjukkan bidang / jenis untuk perusahaan itu.
Ini adalah tampilannya di Firebase.com. Anda harus belajar melakukannya di mana pun yang Anda pilih.
sumber
Jika Anda sering mengalami permintaan bidang khusus, saya akan memodelkannya dengan database. Buat tabel yang menyimpan metadata tentang setiap bidang kustom, CompanyCustomField (milik siapa, tipe data, dll.) Dan tabel lain CompanyCustomFieldValues yang berisi CustomerId, FieldId, dan nilainya. Jika Anda menggunakan sesuatu seperti Microsoft Sql Server, saya akan memiliki kolom nilai menjadi tipe data sql_variant.
Tentu saja ini tidak mudah karena Anda akan membutuhkan antarmuka yang memungkinkan admin menentukan bidang khusus untuk setiap pelanggan, dan antarmuka lain yang benar-benar menggunakan metadata ini untuk membangun UI untuk mengumpulkan nilai-nilai bidang. Dan jika Anda memiliki persyaratan lain, seperti pengelompokan bidang bersama-sama atau kebutuhan untuk melakukan jenis daftar pilih bidang Anda harus mengakomodasi itu dengan lebih banyak metadata / tabel lain (misalnya, CompanyCustomFieldPickListOptions).
Ini bukan hal sepele, tetapi memiliki keuntungan karena tidak memerlukan perubahan database / perubahan kode untuk setiap bidang kustom baru. Fitur lain dari bidang khusus perlu dikodekan juga (misalnya, jika Anda ingin regex memvalidasi nilai string, atau hanya mengizinkan tanggal antara rentang tertentu, atau jika Anda perlu mengaktifkan satu bidang khusus berdasarkan pada nilai bidang khusus lainnya ).
sumber
Alternatif untuk jawaban lain adalah memiliki tabel yang disebut profile_attrib, atau serupa dengan skema yang sepenuhnya dikelola oleh aplikasi Anda.
Saat atribut khusus ditambahkan, Anda
ALTER TABLE profile_attrib ADD COLUMN like_movie TINYINT(1)
, Anda bisa melarang menghapusnya. Ini akan meminimalkan bergabung Anda, sambil tetap memberikan fleksibilitas.Saya kira bit trade-off adalah aplikasi sekarang perlu mengubah hak istimewa tabel ke database, dan Anda harus pintar dalam membersihkan nama kolom.
sumber
[^\w-]+
seharusnya cukup baik melakukannya, tidak membiarkan apa pun tidak -0-9A-Za-z_-
tetapi ya, sanitasi di sini adalah suatu keharusan untuk melindungi dari kejahatan atau kebodohan.Pertanyaan Anda memiliki banyak solusi potensial. Salah satu solusinya adalah menyimpan attribrutes tambahan sebagai XML. XML dapat disimpan sebagai teks atau jika Anda menggunakan database yang mendukung tipe XML sebagai XML (SQL Server). Menyimpan sebagai teks membatasi kemampuan permintaan Anda (seperti mencari pada atribut khusus), tetapi jika menyimpan dan mengambil adalah semua yang Anda butuhkan maka itu adalah solusi yang bagus. Jika seseorang perlu bertanya, maka menyimpan XML sebagai tipe XML akan menjadi pilihan yang lebih baik (meskipun ini lebih spesifik untuk vendor).
Ini akan memberi seseorang kemampuan untuk menyimpan sejumlah atribut ke pelanggan hanya dengan menambahkan kolom tambahan pada tabel pelanggan. Seseorang dapat menyimpan atribut sebagai hashset atau kamus, seseorang akan kehilangan keamanan jenis karena semuanya akan menjadi string untuk memulai, tetapi jika seseorang memaksakan string format standar untuk tanggal, angka, boolean, itu akan berhasil OK.
Untuk informasi lebih lanjut:
https://msdn.microsoft.com/en-us/library/hh403385.aspx
Jawaban @ WalterMitty juga berlaku, meskipun jika seseorang memiliki banyak pelanggan dengan atribut yang berbeda, seseorang dapat berakhir dengan banyak tabel jika mengikuti model pewarisan. Itu tergantung pada berapa banyak atribut khusus dibagi di antara pelanggan.
sumber
Anda harus menormalkan basis data Anda sehingga Anda memiliki 3 tabel berbeda untuk setiap jenis profil perusahaan. Menggunakan contoh Anda, Anda akan memiliki tabel dengan kolom:
Pendekatan ini mengasumsikan bahwa Anda akan mengetahui bentuk informasi yang ingin disimpan oleh perusahaan sebelumnya dan tidak akan sering berubah. Jika bentuk data tidak diketahui pada waktu desain, mungkin akan lebih baik untuk pergi dengan bidang JSON itu atau database nosql.
sumber
Untuk satu alasan atau yang lain, database adalah satu bidang di mana efek platform bagian dalam paling sering muncul. Ini hanyalah kasus anti-pola yang muncul.
Dalam hal ini, Anda mencoba melawan solusi alami dan benar. Pengguna Perusahaan A bukan pengguna Perusahaan B, dan mereka harus memiliki tabel sendiri untuk bidang mereka sendiri.
Vendor basis data Anda tidak membebani Anda dengan tabel, dan Anda tidak perlu dua kali ruang disk untuk dua kali tabel (pada kenyataannya, memiliki dua tabel lebih efisien karena Anda tidak menyimpan atribut A untuk pengguna B. Bahkan menyimpan hanya NULLs membutuhkan ruang).
Tentu saja, jika ada bidang umum yang cukup, Anda dapat memasukkannya ke dalam tabel Pengguna bersama, dan memiliki kunci asing di setiap tabel pengguna khusus perusahaan. Ini adalah struktur yang sangat sederhana sehingga tidak ada pengoptimal kueri basis data yang berjuang dengannya. GABUNGAN yang diperlukan sepele.
sumber
Solusi saya berasumsi bahwa Anda akan memanggil kueri ini dari suatu program dan Anda harus dapat melakukan pemrosesan posting. Anda dapat memiliki kolom berikut:
CUSTOM_VALUES akan berupa kunci penyimpanan string dan pasangan nilai. kunci akan menjadi nama kolom dan nilai akan menjadi nilai kolom misalnya
dalam CUSTOM_VALUES ini Anda hanya akan menyimpan informasi yang ada. Saat Anda kueri dari program, Anda dapat memisahkan string ini dan menggunakannya.
Saya telah menggunakan logika ini dan berfungsi dengan baik, hanya saja Anda harus menerapkan logika penyaringan dalam kode dan bukan dalam kueri.
sumber