Bagaimana cara mendesain basis data untuk Bidang yang Ditentukan Pengguna?

145

Persyaratan saya adalah:

  • Harus dapat menambahkan secara dinamis bidang yang ditentukan pengguna dari semua tipe data
  • Harus dapat meminta UDF dengan cepat
  • Harus dapat melakukan perhitungan pada UDF berdasarkan tipe data
  • Harus dapat mengurutkan UDF berdasarkan tipe data

Informasi lainnya:

  • Saya mencari kinerja terutama
  • Ada beberapa juta catatan Master yang dapat dilampirkan data UDF
  • Ketika saya terakhir memeriksa, ada lebih dari 50 juta catatan UDF di database kami saat ini
  • Sebagian besar waktu, UDF hanya melekat pada beberapa ribu catatan Master, tidak semuanya
  • UDF tidak digabungkan atau digunakan sebagai kunci. Itu hanya data yang digunakan untuk kueri atau laporan

Pilihan:

  1. Buat tabel besar dengan StringValue1, StringValue2 ... IntValue1, IntValue2, ... dll. Saya benci ide ini, tetapi akan mempertimbangkannya jika seseorang dapat mengatakan kepada saya bahwa itu lebih baik daripada ide-ide lain dan mengapa.

  2. Buat tabel dinamis yang menambahkan kolom baru sesuai permintaan sesuai kebutuhan. Saya juga tidak menyukai ide ini karena saya merasa kinerja akan lambat kecuali Anda mengindeks setiap kolom.

  3. Buat tabel tunggal yang berisi UDFName, UDFDataType, dan Value. Saat UDF baru ditambahkan, hasilkan Tampilan yang menarik hanya data itu dan mem-parsingnya ke jenis apa pun yang ditentukan. Item yang tidak memenuhi kriteria parsing mengembalikan NULL.

  4. Buat beberapa tabel UDF, satu per tipe data. Jadi kita akan memiliki tabel untuk UDFStrings, UDFDates, dll. Mungkin akan melakukan hal yang sama seperti # 2 dan menghasilkan otomatis Tampilan kapan saja bidang baru ditambahkan

  5. XML DataTypes? Saya belum pernah bekerja dengan ini sebelumnya tetapi telah melihat mereka disebutkan. Tidak yakin apakah mereka memberi saya hasil yang saya inginkan, terutama dengan kinerja.

  6. Sesuatu yang lain

Rachel
sumber
7
Martin Fowler merekomendasikan 2 (skema yang dapat diperbarui
Neil McGuigan
Lihat juga pertanyaan StackOverflow pada skema database dinamis .
FloverOwe

Jawaban:

49

Jika kinerja adalah perhatian utama, saya akan memilih # 6 ... sebuah tabel per UDF (sungguh, ini adalah varian dari # 2). Jawaban ini secara khusus disesuaikan dengan situasi ini dan deskripsi distribusi data dan pola akses yang dijelaskan.

Pro:

  1. Karena Anda menunjukkan bahwa beberapa UDF memiliki nilai untuk sebagian kecil dari keseluruhan kumpulan data, tabel terpisah akan memberi Anda kinerja terbaik karena tabel itu hanya akan sebesar yang diperlukan untuk mendukung UDF. Hal yang sama berlaku untuk indeks terkait.

  2. Anda juga mendapatkan peningkatan kecepatan dengan membatasi jumlah data yang harus diproses untuk agregasi atau transformasi lainnya. Memisahkan data menjadi beberapa tabel memungkinkan Anda melakukan agregasi dan analisis statistik lainnya pada data UDF, kemudian bergabung dengan hasil itu ke tabel utama melalui kunci asing untuk mendapatkan atribut yang tidak dikumpulkan.

  3. Anda dapat menggunakan nama tabel / kolom yang mencerminkan apa sebenarnya data tersebut.

  4. Anda memiliki kontrol penuh untuk menggunakan tipe data, memeriksa batasan, nilai default, dll. Untuk menentukan domain data. Jangan meremehkan hit performa yang dihasilkan dari konversi tipe data on-the-fly. Kendala tersebut juga membantu pengoptimal permintaan RDBMS mengembangkan rencana yang lebih efektif.

  5. Jika Anda perlu menggunakan kunci asing, integritas referensial deklaratif bawaan jarang dilakukan oleh penegakan batasan tingkat pemicu atau aplikasi.

Cons:

  1. Ini bisa membuat banyak tabel. Menegakkan pemisahan skema dan / atau konvensi penamaan akan meringankan ini.

  2. Ada lebih banyak kode aplikasi yang diperlukan untuk mengoperasikan definisi dan manajemen UDF. Saya berharap ini masih kurang kode yang dibutuhkan daripada untuk opsi asli 1, 3, & 4.

Pertimbangan Lainnya:

  1. Jika ada sesuatu tentang sifat data yang masuk akal bagi UDF untuk dikelompokkan, itu harus didorong. Dengan begitu, elemen-elemen data tersebut dapat digabungkan menjadi satu tabel. Misalnya, Anda memiliki UDF untuk warna, ukuran, dan biaya. Kecenderungan dalam data adalah sebagian besar contoh data ini terlihat

     'red', 'large', 45.03 

    daripada

     NULL, 'medium', NULL

    Dalam kasus seperti itu, Anda tidak akan dikenakan penalti kecepatan yang terlihat dengan menggabungkan 3 kolom dalam 1 tabel karena beberapa nilai akan NULL dan Anda menghindari membuat 2 tabel lagi, yang merupakan 2 gabungan lebih sedikit yang diperlukan ketika Anda perlu mengakses semua 3 kolom .

  2. Jika Anda menabrak dinding kinerja dari UDF yang padat dan sering digunakan, maka itu harus dipertimbangkan untuk dimasukkan dalam tabel master.

  3. Desain tabel logis dapat membawa Anda ke titik tertentu, tetapi ketika jumlah catatan benar-benar besar, Anda juga harus mulai melihat opsi tabel partisi apa yang disediakan oleh RDBMS pilihan Anda.

Phil Helmer
sumber
1
Daftar periksa! Di dalam lelucon antara aku dan Phil, kuharap itu tidak melanggar aturan.
GunnerL3510
Terima kasih, saya pikir saya akan melakukan beberapa variasi. Sebagian besar data UDF kami berasal dari bidang impor yang tidak dipetakan yang perlu tetap ada untuk tujuan referensi saja, jadi saya ingin meletakkannya dalam satu tabel. UDF lain didefinisikan sesuai kebutuhan (saya tidak dapat mengidentifikasinya terlebih dahulu .. mereka biasanya dibuat ketika kami mengubah beberapa proses atau memutuskan untuk melacak sesuatu yang khusus selama beberapa bulan) dan biasanya digunakan dalam kueri. Saya pikir saya akan membuat tabel terpisah untuk setiap unit logis dari nilai-nilai ini.
Rachel
Saya bekerja dengan tabel yang memiliki tanggal / versi UDF, saya menggunakan metode ini, stackoverflow.com/a/123481/328968 , untuk mendapatkan nilai-nilai terbaru.
Peter
22

Saya telah menulis tentang masalah ini banyak . Solusi paling umum adalah antipattern Entity-Attribute-Value, yang mirip dengan apa yang Anda gambarkan dalam opsi # 3. Hindari desain ini seperti wabah .

Apa yang saya gunakan untuk solusi ini ketika saya membutuhkan bidang khusus yang benar-benar dinamis adalah menyimpannya dalam gumpalan XML, sehingga saya dapat menambahkan bidang baru kapan saja. Tetapi untuk membuatnya cepat, buat juga tabel tambahan untuk setiap bidang yang perlu Anda cari atau sortir (Anda bukan tabel per bidang - hanya tabel per bidang yang dapat dicari ). Ini kadang-kadang disebut desain indeks terbalik.

Anda dapat membaca artikel yang menarik dari 2009 tentang solusi ini di sini: http://backchannel.org/blog/friendfeed-schemaless-mysql

Atau Anda dapat menggunakan database berorientasi dokumen, di mana Anda diharapkan memiliki bidang khusus per dokumen. Saya akan memilih Solr .

Bill Karwin
sumber
1
Bisakah Anda jelaskan mengapa saya harus menghindari opsi # 3? Saya melihat beberapa contoh Anda, tetapi mereka benar-benar tidak sama dengan apa yang saya coba lakukan. Saya hanya ingin tempat untuk menyimpan data tambahan, bukan tempat untuk menyimpan semua atribut.
Rachel
2
Sebagai permulaan, siapa yang akan Anda buat atribut TIDAK NULL? Bagaimana Anda membuat atribut UNIK tanpa membuat semua atribut UNIK? Itu berlangsung dari sana. Anda akhirnya menulis kode aplikasi untuk menyediakan fitur yang sudah disediakan RDBMS untuk Anda, bahkan sampai harus menulis semacam kelas pemetaan untuk hanya memasukkan catatan entitas logis dan mengambilnya kembali.
Bill Karwin
2
Jawaban singkatnya adalah "jangan mencampur data dan metadata." Membuat kolom varchar untuk fieldnameatau tablenamemenyimpan pengidentifikasi metadata sebagai string data, dan itulah awal dari banyak masalah. Juga lihat en.wikipedia.org/wiki/Inner-platform_effect
Bill Karwin
2
@ Thomas: Dalam desain indeks terbalik, Anda dapat menggunakan solusi skema standar untuk tipe data, dan kendala seperti UNIK dan KUNCI ASING. Itu tidak berfungsi sama sekali saat Anda menggunakan EAV. Saya setuju saham indeks terbalik dengan EAV sifat menjadi non-relasional hanya karena mendukung atribut berbeda per baris, tapi itu titik kompromi.
Bill Karwin
2
@ thitami, Apa yang saya pelajari selama bertahun-tahun adalah bahwa solusi apa pun mungkin yang tepat untuk aplikasi Anda. Bahkan EAV mungkin menjadi solusi paling buruk untuk beberapa aplikasi tertentu. Anda tidak dapat memilih strategi optimasi tanpa mengetahui pertanyaan Anda. Setiap jenis pengoptimalan meningkatkan kueri tertentu dengan mengorbankan kueri lainnya.
Bill Karwin
10

Saya kemungkinan besar akan membuat tabel dari struktur berikut:

  • Nama varchar
  • Jenis varchar
  • NumberValue desimal
  • varchar StringValue
  • tanggal DateValue

Jenis pastinya tergantung pada kebutuhan Anda (dan tentu saja pada dbms yang Anda gunakan). Anda juga bisa menggunakan bidang NumberValue (desimal) untuk int dan boolean. Anda mungkin perlu jenis lain juga.

Anda memerlukan beberapa tautan ke catatan Master yang memiliki nilai. Mungkin paling mudah dan tercepat untuk membuat tabel bidang pengguna untuk setiap tabel master dan menambahkan kunci asing sederhana. Dengan cara ini Anda bisa memfilter catatan master menurut bidang pengguna dengan mudah dan cepat.

Anda mungkin ingin memiliki semacam informasi meta data. Jadi, Anda berakhir dengan yang berikut:

Tabel UdfMetaData

  • int id
  • Nama varchar
  • Jenis varchar

Tabel MasterUdfValues

  • int Master_FK
  • int MetaData_FK
  • NumberValue desimal
  • varchar StringValue
  • tanggal DateValue

Apa pun yang Anda lakukan, saya tidak akan mengubah struktur tabel secara dinamis. Ini adalah mimpi buruk pemeliharaan. Saya juga tidak akan menggunakan struktur XML, mereka terlalu lambat.

Stefan Steinegger
sumber
Saya menyukai strategi Anda, dan mungkin memilihnya tetapi pada tahun 2017, Apakah Anda akan memilih sesuatu yang berbeda? seperti json
maztt
Dalam proyek kami, kami menerapkan struktur data kami sendiri yang bersambung ke sesuatu yang mirip dengan json. Ini fitur antarmuka mengetik untuk membaca dan menulis data tanpa casting dan dengan integrasi bahasa pemrograman yang hebat. Bagus sekali. Ini memiliki masalah yang sama dengan semua "dokumen" dalam database. Sulit untuk meminta nilai spcific dan tidak dapat dengan mudah merujuk data di luar "dokumen". Tergantung pada penggunaannya, keduanya bahkan tidak menjadi masalah.
Stefan Steinegger
Selain itu, apa yang saya usulkan pada tahun 2011 adalah IMHO masih merupakan solusi yang valid.
Stefan Steinegger
10

Ini terdengar seperti masalah yang mungkin lebih baik diselesaikan dengan solusi non-relasional, seperti MongoDB atau CouchDB.

Keduanya memungkinkan untuk perluasan skema dinamis sekaligus memungkinkan Anda untuk mempertahankan integritas tuple yang Anda cari.

Saya setuju dengan Bill Karwin, model EAV bukan merupakan pendekatan untuk Anda. Menggunakan pasangan nama-nilai dalam sistem relasional tidak buruk secara intrinsik, tetapi hanya berfungsi dengan baik ketika pasangan nama-nilai membuat tupel informasi yang lengkap. Saat menggunakannya memaksa Anda untuk merekonstruksi meja secara dinamis pada saat run-time, semua hal mulai menjadi sulit. Permintaan menjadi latihan dalam pemeliharaan poros atau memaksa Anda untuk mendorong rekonstruksi tuple ke lapisan objek.

Anda tidak bisa menentukan apakah nilai nol atau hilang adalah entri yang valid atau kurang masuk tanpa menyematkan aturan skema di lapisan objek Anda.

Anda kehilangan kemampuan untuk mengelola skema Anda secara efisien. Apakah 100 karakter varchar jenis yang tepat untuk bidang "nilai"? 200 karakter? Haruskah itu nvarchar saja? Ini bisa menjadi pertukaran yang sulit dan yang berakhir dengan Anda harus menempatkan batasan buatan pada sifat dinamis set Anda. Sesuatu seperti "Anda hanya dapat memiliki x bidang yang ditentukan pengguna dan masing-masing hanya dapat berupa karakter y.

Dengan solusi berorientasi dokumen, seperti MongoDB atau CouchDB, Anda mempertahankan semua atribut yang terkait dengan pengguna dalam satu tupel. Karena bergabung bukan merupakan masalah, hidup bahagia, karena tidak satu pun dari keduanya ini yang cocok dengan joins, meskipun hype. Pengguna Anda dapat mendefinisikan atribut sebanyak yang mereka inginkan (atau Anda akan memungkinkan) dengan panjang yang tidak sulit untuk dikelola sampai Anda mencapai sekitar 4MB.

Jika Anda memiliki data yang memerlukan integritas tingkat ACID, Anda dapat mempertimbangkan pemecahan solusi, dengan data integritas tinggi yang tinggal di database relasional Anda dan data dinamis yang tinggal di toko non-relasional.

Biksu Data
sumber
6

Bahkan jika Anda menyediakan untuk pengguna menambahkan kolom khusus, itu tidak selalu menjadi kasus bahwa permintaan pada kolom tersebut akan berkinerja baik. Ada banyak aspek yang masuk ke desain kueri yang memungkinkan mereka untuk berkinerja baik, yang paling penting adalah spesifikasi yang tepat tentang apa yang harus disimpan di tempat pertama. Jadi, pada dasarnya, apakah Anda ingin mengizinkan pengguna untuk membuat skema tanpa memikirkan spesifikasi dan dapat dengan cepat memperoleh informasi dari skema itu? Jika demikian, maka tidak mungkin solusi semacam itu akan menskalakan dengan baik terutama jika Anda ingin memungkinkan pengguna untuk melakukan analisis numerik pada data.

Pilihan 1

IMO pendekatan ini memberi Anda skema tanpa pengetahuan tentang apa artinya skema yang merupakan resep untuk bencana dan mimpi buruk bagi perancang laporan. Yaitu, Anda harus memiliki meta data untuk mengetahui kolom apa yang menyimpan data apa. Jika metadata itu kacau, ia berpotensi menyemprot data Anda. Plus, membuatnya mudah untuk menempatkan data yang salah di kolom yang salah. ("Apa? String1 berisi nama biara? Kupikir itu obat favorit Chalie Sheen.")

Opsi 3,4,5

IMO, persyaratan 2, 3, dan 4 menghilangkan segala variasi EAV. Jika Anda perlu menanyakan, mengurutkan, atau melakukan perhitungan pada data ini, maka EAV adalah impian Cthulhu dan mimpi buruk tim pengembangan Anda dan DBA. EAV's akan membuat hambatan dalam hal kinerja dan tidak akan memberi Anda integritas data yang Anda butuhkan untuk dengan cepat mendapatkan informasi yang Anda inginkan. Kueri akan dengan cepat beralih ke simpul Gordian crosstab.

Opsi 2,6

Itu benar-benar menyisakan satu pilihan: kumpulkan spesifikasi dan kemudian bangun skema.

Jika klien menginginkan kinerja terbaik pada data yang ingin mereka simpan, maka mereka harus melalui proses bekerja dengan pengembang untuk memahami kebutuhan mereka sehingga disimpan seefisien mungkin. Itu masih bisa disimpan dalam tabel terpisah dari sisa tabel dengan kode yang secara dinamis membangun formulir berdasarkan skema tabel. Jika Anda memiliki database yang memungkinkan properti diperluas pada kolom, Anda bahkan bisa menggunakannya untuk membantu pembuat formulir menggunakan label yang bagus, tooltips dll. Sehingga semua yang diperlukan adalah menambahkan skema. Either way, untuk membangun dan menjalankan laporan secara efisien, data perlu disimpan dengan benar. Jika data yang dimaksud akan memiliki banyak nol, beberapa basis data memiliki kemampuan untuk menyimpan jenis informasi itu. Sebagai contoh,

Jika ini hanya sekantong data yang tidak boleh dilakukan analisis, pemfilteran, atau pengurutan, saya akan mengatakan beberapa variasi EAV yang dapat melakukan trik. Namun, mengingat persyaratan Anda, solusi paling efisien adalah mendapatkan spesifikasi yang tepat bahkan jika Anda menyimpan kolom baru ini di tabel terpisah dan membuat formulir secara dinamis dari tabel tersebut.

Kolom Jarang

Thomas
sumber
5
  1. Buat beberapa tabel UDF, satu per tipe data. Jadi kita akan memiliki tabel untuk UDFStrings, UDFDates, dll. Mungkin akan melakukan hal yang sama seperti # 2 dan menghasilkan otomatis Tampilan kapan saja bidang baru ditambahkan

Menurut penelitian saya beberapa tabel berdasarkan tipe data tidak akan membantu Anda dalam kinerja. Terutama jika Anda memiliki data massal, seperti catatan 20K atau 25K dengan 50+ UDF. Kinerja adalah yang terburuk.

Anda harus menggunakan tabel tunggal dengan banyak kolom seperti:

varchar Name
varchar Type
decimal NumberValue
varchar StringValue
date DateValue
Kontraktor Amit
sumber
Ini harus benar dan terunggul. Jawaban sebelumnya pada tahun 2011 oleh Phil tidak lagi menjadi saran yang bagus hari ini 2016.
Yap Kai Lun Leon
Bisakah saya mendapatkan contoh sederhana tentang bagaimana melakukan proses seperti itu dalam sql.?
Niroj
Maaf atas jawaban yang terlambat, tetapi Anda menginginkan struktur basis data yang sama. Saya tidak mendapatkan Anda @ Niroj. Bisakah Anda jelaskan secara rinci seperti apa yang Anda inginkan.
Kontraktor Amit
4

Ini adalah situasi yang bermasalah, dan tidak ada solusi yang tampak "benar". Namun opsi 1 mungkin yang terbaik baik dalam hal kesederhanaan maupun dalam hal kinerja.

Ini juga solusi yang digunakan dalam beberapa aplikasi perusahaan komersial.

EDIT

opsi lain yang tersedia sekarang, tetapi tidak ada (atau setidaknya tidak matang) ketika pertanyaan itu asli ditanyakan adalah menggunakan bidang json di DB.

banyak DB relasional sekarang mendukung bidang berbasis json (yang dapat menyertakan daftar sub bidang yang dinamis) dan memungkinkan untuk menanyakannya

postgress

mysql

Ophir Yoktan
sumber
1
Saya benci ide membuat ratusan kolom yang mungkin tidak terpakai. Itu bertentangan dengan apa yang telah saya pelajari dan baca tentang desain database SQL. Saat ini, kami memiliki lebih dari 1.300 nilai yang ditentukan pengguna yang berbeda, meskipun banyak dari mereka adalah duplikat dari item yang ada yang diberi nama berbeda.
Rachel
1300 UDF berbeda untuk satu meja? apakah setiap pengguna memiliki opsi untuk menambahkan UDF, atau hanya beberapa jenis pengguna daya?
Ophir Yoktan
Ini bagian dari proses impor ... itu menambahkan data yang tidak dipetakan ke bidang yang ditentukan pengguna. Karena tidak ada yang meluangkan waktu untuk memetakan data yang belum dipetakan ke bidang UDF yang ada, itu hanya membuat yang baru dan selama bertahun-tahun banyak yang telah ditambahkan.
Rachel
2

Saya sudah memiliki pengalaman atau 1, 3 dan 4 dan mereka semua berakhir berantakan, dengan tidak jelas apa data atau benar-benar rumit dengan semacam kategorisasi lunak untuk memecah data ke dalam jenis catatan dinamis.

Saya akan tergoda untuk mencoba XML, Anda harus dapat menegakkan skema terhadap konten xml untuk memeriksa pengetikan data dll yang akan membantu memegang set perbedaan data UDF. Dalam versi SQL server yang lebih baru, Anda dapat mengindeks pada bidang XML, yang seharusnya membantu kinerja. (lihat http://blogs.technet.com/b/josebda/archive/2009/03/23/sql-server-2008-xml-indexing.aspx ) misalnya

Jon Egerton
sumber
Jujur, saya belum melihat ke XML sama sekali. Kelemahan utama dari hal itu adalah saya harus belajar cara kerjanya dan cara mengatasinya, dan saya dengar kinerja bisa lebih buruk daripada opsi lain
Rachel
1
Saya akan menghindari menggunakan xml untuk ini: ia dapat melakukan pekerjaan, dan saya telah mengimplementasikan sesuatu seperti ini di xml di masa lalu, tetapi kinerjanya menjadi sangat buruk ketika struktur data tumbuh, dan kompleksitas kode yang tinggi.
Kell
2

Jika Anda menggunakan SQL Server, jangan mengabaikan tipe sqlvariant. Ini cukup cepat dan harus melakukan pekerjaan Anda. Basis data lain mungkin memiliki sesuatu yang serupa.

Tipe data XML tidak begitu baik karena alasan kinerja. Jika Anda melakukan perhitungan di server maka Anda harus terus-menerus membatalkan deserialisasi.

Opsi 1 terdengar buruk dan terlihat kasar, tetapi kinerja-bijaksana bisa menjadi taruhan terbaik Anda. Saya telah membuat tabel dengan kolom bernama Field00-Field99 sebelumnya karena Anda tidak bisa mengalahkan kinerja. Anda mungkin perlu mempertimbangkan kinerja INSERT Anda juga, dalam hal ini juga adalah untuk pergi untuk. Anda selalu dapat membuat Tampilan di tabel ini jika Anda ingin terlihat rapi!

Tim Rogers
sumber
Terima kasih, saya akan melihat varian SQL. Kekhawatiran terbesar saya adalah kinerja dan saya tidak yakin bagaimana cara mengatasinya, terutama jika kita berbicara tentang lebih dari 50 juta baris
Rachel
Baru tahu sql_varients tidak dapat digunakan dengan klausa LIKE ... itu kerugian besar bagi saya. Tentu saja, jika saya membuat tampilan untuk setiap UDF maka saya bisa melemparkannya ke tipe data yang sesuai berdasarkan SQL_VARIANT_PROPERTY (nilai, 'TipeTipe') ... masih, sepertinya ini adalah kinerja yang buruk
Rachel
Anda dapat menggunakan LIKE, tetapi Anda harus memberikan nilainya terlebih dahulu. LIKE hanya berfungsi pada varchars sehingga Anda harus mengirimkan sql_variant Anda ke varchar. Selama Anda tahu apa apakah UDF Anda adalah varchar (mis. Karena jenisnya disimpan di tempat lain), Anda dapat memfilter semua baris Anda ke varchars lalu melemparkan dan menjalankan kueri LIKE: misalnya. pilih * FROM MyTable di mana variant_type = 'v' Cast (variant_value as varchar (max)) SUKA 'Blah%' Dengan cara ini, Anda tidak mengonversi int dan seterusnya ke string yang akan memperlambat Anda.
Tim Rogers
Saya perlu menjalankan beberapa tes untuk melihat bagaimana kinerjanya, terutama dengan jutaan baris. Tahu ada artikel online tentang kinerja menggunakan sql_varients? Apalagi dengan casting dan jumlah rekaman yang sangat besar?
Rachel
1

SharePoint menggunakan opsi 1 dan memiliki kinerja yang masuk akal.

Nathan DeWitt
sumber
1

Saya telah mengelola ini dengan sangat sukses di masa lalu tanpa menggunakan salah satu opsi ini (opsi 6? :)).

Saya membuat model bagi pengguna untuk bermain (simpan sebagai xml dan mengekspos melalui alat pemodelan kustom) dan dari tabel yang dihasilkan model dan pandangan untuk bergabung dengan tabel dasar dengan tabel data yang ditentukan pengguna. Jadi setiap jenis akan memiliki tabel dasar dengan data inti dan tabel pengguna dengan bidang yang ditentukan pengguna.

Ambil dokumen sebagai contoh: bidang tipikal adalah nama, tipe, tanggal, penulis, dll. Ini akan masuk ke tabel inti. Kemudian pengguna akan menentukan jenis dokumen khusus mereka sendiri dengan bidang mereka sendiri, seperti contract_end_date, renewal_clause, bla bla bla. Untuk dokumen yang ditentukan pengguna itu akan ada tabel dokumen inti, tabel xcontract, digabung dengan kunci primer bersama (jadi kunci primer xcontracts juga asing pada kunci utama tabel inti). Lalu saya akan menghasilkan tampilan untuk membungkus dua tabel ini. Performa saat bertanya cepat. aturan bisnis tambahan juga dapat dimasukkan ke dalam tampilan. Ini bekerja sangat baik untuk saya.

Kell
sumber
1

Basis data kami mendukung aplikasi SaaS (perangkat lunak helpdesk) di mana pengguna memiliki lebih dari 7k "bidang khusus". Kami menggunakan pendekatan gabungan:

  1. (EntityID, FieldID, Value)tabel untuk mencari data
  2. bidang JSON dalam entitiestabel, yang menampung semua nilai entitas, yang digunakan untuk menampilkan data. (dengan cara ini Anda tidak perlu satu juta BERGABUNG untuk mendapatkan nilai nilai).

Anda selanjutnya dapat membagi # 1 untuk memiliki "tabel per tipe data" seperti jawaban ini menunjukkan, dengan cara ini Anda bahkan dapat mengindeks UDF Anda.

PS Sepasang kata untuk mempertahankan pendekatan "Entity-Attribute-Value" yang semua orang terus bashing. Kami telah menggunakan # 1 tanpa # 2 selama beberapa dekade dan itu berhasil dengan baik. Terkadang itu keputusan bisnis. Apakah Anda punya waktu untuk menulis ulang aplikasi dan mendesain ulang db atau Anda dapat membuang beberapa dolar di server cloud, yang benar-benar murah hari ini? Omong-omong, ketika kami menggunakan pendekatan # 1, DB kami memegang jutaan entitas, diakses oleh 100-an ribu pengguna, dan server db dual-core 16GB berjalan dengan baik

Alex
sumber
Hai @ Alex, saya menemukan masalah serupa. Jika saya mengerti dengan baik Anda sudah mendapat: 1) custom_fieldstabel yang menyimpan nilai seperti 1 => last_concert_year, 2 => band, 3 => musicdan kemudian custom_fields_valuestabel dengan nilai 001, 1, 1976 002, 1, 1977 003, 2, Iron Maiden003, 3 , Metal Semoga contohnya masuk akal bagi Anda dan maaf karena formatnya!
thitami
@ thitami tidak persis. Mengikuti contoh Anda: Saya punya bandstabel dengan satu baris 1,'Iron Maiden'kemudian custom_fieldsdengan baris 1,'concert_year' | 2,'music'lalu custom_fields_valuesdengan baris1,1,'1977'|1,2,'metal'
Alex
0

Dalam komentar yang saya lihat Anda mengatakan bahwa bidang UDF adalah untuk membuang data yang diimpor yang tidak dipetakan dengan benar oleh pengguna.

Mungkin pilihan lain adalah untuk melacak jumlah UDF yang dibuat oleh setiap pengguna dan memaksa mereka untuk menggunakan kembali bidang dengan mengatakan mereka dapat menggunakan 6 (atau beberapa batas acak lain yang sama) bidang kustom teratas.

Ketika Anda dihadapkan dengan masalah penataan basis data seperti ini, seringkali yang terbaik adalah kembali ke desain dasar aplikasi (sistem impor dalam kasus Anda) dan menempatkan beberapa pengekangan di atasnya.

Sekarang yang akan saya lakukan adalah opsi 4 (EDIT) dengan tambahan tautan ke pengguna:

general_data_table
id
...


udfs_linked_table
id
general_data_id
udf_id


udfs_table
id
name
type
owner_id --> Use this to filter for the current user and limit their UDFs
string_link_id --> link table for string fields
int_link_id
type_link_id

Sekarang pastikan untuk membuat tampilan untuk mengoptimalkan kinerja dan memperbaiki indeks Anda. Tingkat normalisasi ini membuat jejak kaki DB lebih kecil, tetapi aplikasi Anda lebih kompleks.

Wouter Simons
sumber
0

Saya akan merekomendasikan # 4 karena sistem jenis ini digunakan di Magento yang merupakan platform CMS e-commerce yang sangat terakreditasi. Gunakan tabel tunggal untuk mendefinisikan bidang khusus Anda menggunakan kolom ID kolom & label . Kemudian, memiliki tabel terpisah untuk setiap tipe data dan dalam masing-masing tabel tersebut memiliki indeks yang diindeks oleh fieldId dan kolom nilai tipe data . Lalu, dalam kueri Anda, gunakan sesuatu seperti:

SELECT *
FROM FieldValues_Text
WHERE fieldId IN (
    SELECT fieldId FROM Fields WHERE userId=@userId
)
AND value LIKE '%' + @search + '%'

Ini akan memastikan kinerja terbaik untuk tipe yang ditentukan pengguna menurut saya.

Dalam pengalaman saya, saya telah bekerja di beberapa situs web Magento yang melayani jutaan pengguna per bulan, menampung ribuan produk dengan atribut produk khusus, dan basis data menangani beban kerja dengan mudah, bahkan untuk pelaporan.

Untuk pelaporan, Anda bisa menggunakan PIVOTuntuk mengonversi nilai label tabel Fields Anda menjadi nama kolom, lalu pivot hasil kueri Anda dari setiap tabel tipe data ke dalam kolom pivot tersebut.

Tandai Entingh
sumber