Ini disebut Entity-Attribute-Value (juga kadang-kadang 'pasangan nama-nilai') dan ini merupakan kasus klasik "pasak bundar dalam lubang persegi" ketika orang menggunakan pola EAV dalam database relasional.
Berikut adalah daftar mengapa Anda tidak boleh menggunakan EAV:
- Anda tidak dapat menggunakan tipe data. Tidak masalah jika nilainya adalah tanggal, angka atau uang (desimal). Itu akan selalu dipaksa untuk varchar. Ini bisa berupa apa saja dari masalah kinerja kecil hingga sakit usus besar (pernah harus mengejar variasi satu sen dalam laporan bulanan roll-up?).
- Anda tidak dapat (dengan mudah) menegakkan batasan. Dibutuhkan jumlah kode yang konyol untuk menegakkan "Setiap orang harus memiliki ketinggian antara 0 dan 3 meter" atau "Usia tidak boleh nol dan> = 0", berlawanan dengan 1-2 baris yang masing-masing dari batasan tersebut akan menjadi dalam sistem yang dimodelkan dengan benar.
- Terkait dengan di atas, Anda tidak dapat dengan mudah menjamin bahwa Anda mendapatkan informasi yang Anda butuhkan untuk setiap klien (usia mungkin hilang dari satu, maka yang berikutnya mungkin akan kehilangan tinggi badan mereka, dll.). Anda dapat melakukannya, tetapi jauh lebih sulit daripada itu
SELECT height, weight, age FROM Client where height is null or weight is null
.
- Terkait lagi, data duplikat jauh lebih sulit untuk dideteksi (apa yang terjadi jika mereka memberi Anda dua usia untuk satu klien? De-EAVing data, seperti di bawah ini, akan memberi Anda dua baris hasil jika Anda memiliki satu atribut yang berlipat ganda. Jika satu klien memiliki dua entri terpisah untuk dua atribut, Anda akan mendapatkan empat baris dari kueri di bawah).
- Anda bahkan tidak dapat menjamin bahwa nama atributnya konsisten. "Age_yr" mungkin menjadi "AGE_IN_YEARS" atau "age". (Harus diakui ini bukan masalah saat Anda menerima ekstrak versus ketika orang memasukkan data, tetapi tetap saja.)
- Segala jenis permintaan nontrivial adalah bencana total. Untuk menghubungkan kembali sistem EAV tiga atribut sehingga Anda dapat menanyakannya secara rasional membutuhkan tiga gabungan dari tabel EAV.
Membandingkan:
SELECT cID.ID AS [ID], cH.Value AS [Height], cW.Value AS [Weight], cA.Value AS [Age]
FROM (SELECT DISTINCT ID FROM Client) cID
LEFT OUTER JOIN
Client cW ON cID.ID = cW.ID AND cW.Metric = "Wt_kg"
LEFT OUTER JOIN
Client cH ON cID.ID = cH.ID AND cW.Metric = "Ht_cm"
LEFT OUTER JOIN
Client cA ON cID.ID = cA.ID AND cW.Metric = "Age_yr"
Untuk:
SELECT c.ID, c.Ht_cm, c.Wt_kg, c.Age_yr
FROM Client c
Berikut adalah daftar (sangat singkat) kapan Anda harus menggunakan EAV:
- Ketika sama sekali tidak ada jalan keluar dan Anda harus mendukung data tanpa skema di database Anda.
- Ketika Anda hanya perlu menyimpan "barang" dan jangan berharap harus membutuhkannya dalam bentuk yang lebih terstruktur. Namun waspadalah, monster itu bernama "mengubah persyaratan".
Aku tahu aku hanya menghabiskan seluruh posting ini merinci mengapa EAV adalah ide yang buruk dalam banyak kasus - tetapi ada yang beberapa kasus di mana diperlukan / tidak dapat dihindari. Namun, sebagian besar waktu (termasuk contoh di atas), itu akan jauh lebih merepotkan daripada nilainya. Jika Anda memiliki persyaratan untuk dukungan luas input data tipe EAV, Anda harus melihat menyimpannya dalam sistem nilai kunci, misalnya Hadoop / HBase, CouchDB, MongoDB, Cassandra, BerkeleyDB.
Nilai Atribut Entitas (EAV)
Ini dianggap sebagai anti-pola oleh banyak orang, termasuk saya.
Berikut adalah alternatif Anda:
menggunakan pewarisan tabel database
menggunakan data XML dan fungsi SQLXML
gunakan database nosql, seperti HBase
sumber
Dalam PostgreSQL, satu cara yang sangat baik untuk menangani struktur EAV adalah modul tambahan
hstore
, tersedia untuk versi 8.4 atau lebih baru. Saya mengutip manual:Sejak Postgres 9.2 ada juga
json
tipe dan sejumlah fungsi untuk digunakan ( sebagian besar ditambahkan dengan 9.3 ).Postgres 9.4 menambahkan tipe data "binary JSON" (sebagian besar unggul!) Ke
jsonb
daftar opsi. Dengan opsi indeks lanjutan.sumber
Jika Anda memiliki database yang menggunakan struktur EAV, dimungkinkan untuk menanyakan data dengan berbagai cara.
@ Simon menjawab sudah menunjukkan bagaimana melakukan kueri menggunakan beberapa gabungan.
Sampel Data yang Digunakan:
Jika Anda menggunakan RDBMS yang memiliki
PIVOT
fungsi ( SQL Server 2005+ / Oracle 11g + ) maka Anda dapat meminta data dengan cara berikut:Lihat SQL Fiddle dengan Demo
Jika Anda tidak memiliki akses ke suatu
PIVOT
fungsi, maka Anda dapat menggunakan fungsi agregat denganCASE
pernyataan untuk mengembalikan data:Lihat SQL Fiddle dengan Demo
Kedua kueri ini akan mengembalikan data dalam hasil:
sumber
Lucu melihat bagaimana model EAV db dikritik dan bahkan dianggap sebagai "anti-pola" oleh beberapa orang.
Sejauh yang saya ketahui, kerugian utama adalah:
Namun, Anda seharusnya tidak membuang solusi ini, dan inilah alasannya:
sumber