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:
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.
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.
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.
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
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.
Sesuatu yang lain
Jawaban:
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:
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.
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.
Anda dapat menggunakan nama tabel / kolom yang mencerminkan apa sebenarnya data tersebut.
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.
Jika Anda perlu menggunakan kunci asing, integritas referensial deklaratif bawaan jarang dilakukan oleh penegakan batasan tingkat pemicu atau aplikasi.
Cons:
Ini bisa membuat banyak tabel. Menegakkan pemisahan skema dan / atau konvensi penamaan akan meringankan ini.
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:
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
daripada
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 .
Jika Anda menabrak dinding kinerja dari UDF yang padat dan sering digunakan, maka itu harus dipertimbangkan untuk dimasukkan dalam tabel master.
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.
sumber
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 .
sumber
fieldname
atautablename
menyimpan pengidentifikasi metadata sebagai string data, dan itulah awal dari banyak masalah. Juga lihat en.wikipedia.org/wiki/Inner-platform_effectSaya kemungkinan besar akan membuat tabel dari struktur berikut:
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
Tabel MasterUdfValues
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.
sumber
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.
sumber
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
sumber
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:
sumber
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
sumber
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
sumber
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!
sumber
SharePoint menggunakan opsi 1 dan memiliki kinerja yang masuk akal.
sumber
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.
sumber
Basis data kami mendukung aplikasi SaaS (perangkat lunak helpdesk) di mana pengguna memiliki lebih dari 7k "bidang khusus". Kami menggunakan pendekatan gabungan:
(EntityID, FieldID, Value)
tabel untuk mencari dataentities
tabel, 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
sumber
custom_fields
tabel yang menyimpan nilai seperti 1 =>last_concert_year
, 2 =>band
, 3 =>music
dan kemudiancustom_fields_values
tabel dengan nilai 001, 1, 1976 002, 1, 1977 003, 2,Iron Maiden
003, 3 ,Metal
Semoga contohnya masuk akal bagi Anda dan maaf karena formatnya!bands
tabel dengan satu baris1,'Iron Maiden'
kemudiancustom_fields
dengan baris1,'concert_year' | 2,'music'
lalucustom_fields_values
dengan baris1,1,'1977'|1,2,'metal'
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:
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.
sumber
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:
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
PIVOT
untuk mengonversi nilai label tabel Fields Anda menjadi nama kolom, lalu pivot hasil kueri Anda dari setiap tabel tipe data ke dalam kolom pivot tersebut.sumber