EAV - Tüm senaryolarda gerçekten kötü mü?


65

Projelerden birinde bazı şeyler için varlık-özellik-değeri (EAV) modelini kullanmayı düşünüyorum , ancak Stack Overflow'taki tüm sorular EAV'ye anti-kalıp denen cevaplarla sonuçlanıyor.

Ama her durumda bunun yanlış olup olmadığını merak ediyorum.

Diyelim ki mağaza ürünü varlığı, mantığa birçok yerde yer alan isim, açıklama, resim ve fiyat gibi ortak özelliklere sahip ve saat ve plaj topu gibi (yarı) benzersiz özelliklere sahip, tamamen farklı yönleriyle tanımlanacak. Bu yüzden EAV, bu (yarı) benzersiz özellikleri depolamak için uygun olacağını düşünüyorum.

Tüm bunlar, ürün listesini göstermek için, ürün tablosunda (EAV'nin dahil olmadığı anlamına gelir) ve sadece bir ürün gösterildiğinde / 5 ürün / vb. Karşılaştırırken yeterli bilgi olduğu varsayılmaktadır. EAV kullanılarak kaydedilen veriler kullanılır.

Magento ticaretinde bu tür bir yaklaşım gördüm ve oldukça popüler, bu yüzden EAV'nın makul olduğu durumlar var mı?


2
@ busy_wait "Entity-Attibute-Value" tabloları - Wikipedia'daki Varlık – özellik – değer modeline bakın .
Ross Patterson,

EAV modelinin gerçekten iyi sonuç verdiğinin bir örneği için Datomic veritabanına bir göz atın. Her şeyi EAVT düzeninde saklar (T bir "zaman damgasıdır", aslında bir işlem kimliği gibidir). Onların [indeksleme belgeleri] (docs.datomic.com/indexes.html) en iyisini gösteriyor gibi görünüyor. Çok iyi çalışan bir EAV örneği için, bkz. Wordpress .
Dan Ross

Yanıtlar:


80

https://web.archive.org/web/20140831134758/http://www.dbforums.com/database-concepts-design/1619660-otlt-eav-design-why-do-people-hate.html

EAV, şemaya gerektiği gibi tanımlanması için geliştiriciye esneklik sağlar ve bu bazı durumlarda iyidir.

Öte yandan, kötü tanımlanmış bir sorgu durumunda çok düşük performans gösterir ve diğer kötü uygulamaları destekleyebilir.

Başka bir deyişle, EAV size kendinizi asmak için yeterli ipi verir ve bu sektörde, işler sizi en düşük karmaşıklık seviyesine göre tasarlamalıdır, çünkü sizi projede değiştiren adam aptal olacak.


32
Son cümleyi sev.
Zohar Peled,

2
Çürük bağlantı Bir yerde önbelleklenmiş bir sürümü var mı?
Wildcard

1
Bağlantıyı takip etme. Sayfa yavaş yükleniyor ve yardımcı değil. Ayrıca, eski tarz forumlar bunun gibi kokuyor. Bunun yerine yığın taşması kullanın! İyi / faydalı cevapları boşaltın ve çöp kutusuna bastırın.
Jess,

29

Özetle, EAV, özellikler listeniz sıkça arttığında veya o kadar büyük olduğunda, çoğu özelliği bir sütun yaparsanız çoğu satır NULL ile doldurulacak kadar büyük olduğunda kullanışlıdır. Bu bağlamın dışında kullanıldığında bir anti-patern olur.


16
"Sık sık" yerine "çalışma zamanında değişiklik yapma imkanı gerekiyor" diyecektim.
Doktor Brown

3
Oldukça iyi anlaşılmış olan "dynamic" (Dinamik) kelimesini kullanarak Doc Brown'ın daha da kısaltılmasını sağlayabiliriz.
Alexander Mills

Dahası "nitelikleriniz ne zaman değişebilir" - "dinamik olarak" bu bağlamda biraz gereksizdir :)
Wranorn

1
Öznitelik değiştirme formunun CREATE TABLEyeni bir öznitelik için bir performans gösterme biçimine sahip olmasından daha faydalı mıdır ?
Damian Yerrick

@DamianYerrick ilginç bir yaklaşım. Bunu üretimde kullandınız mı?
digout

21

Diyelim ki mağaza ürün varlığı, ad, açıklama, resim, fiyat vb. Gibi ortak özelliklere sahiptir, birçok yerde mantıkta yer alır ve saat ve plaj topu gibi (yarı) benzersiz özelliklere sahiptir, saat ve plaj topu gibi tamamen farklı yönleriyle tanımlanacaktır. . Yani EAV, bu (yarı) benzersiz özellikleri depolamak için uygun olacağını düşünüyorum?

Bir EAV yapısının kullanılmasının, ticari kazanç olan çeşitli etkileri vardır.

'Satır için daha az yer kaplıyorsunuz çünkü null' daha 'karmaşık sorgulara ve modele karşı' 100 sütununuz yok '.

Bir EAV'ye sahip olmak, tipik olarak, değerin, herhangi bir veriyi içine alabileceği bir dize olduğu anlamına gelir. Bunun daha sonra geçerlilik ve kısıt kontrolü üzerinde etkileri var. EAV tablosunda bir şey olarak kullanılan pil sayısını koyduğunuz durumu göz önünde bulundurun. C büyüklüğünde pil kullanan ancak 4'ünden az bir el feneri bulmak istiyorsunuz.

select P.sku
from
  products P
  attrib Ab on (P.sku = Ab.sku and Ab.key = "batteries")
  attrib Ac on (P.sku = Ac.sku and Ac.key = "count")
where
  cast(Ac.value as int) < 4
  and Ab.value = 'C'
  ...

Burada farkına varılacak şey, değer üzerinde makul bir endeks kullanamayacağınızdır. Ayrıca, değer sütununu farklı amaçlar için tekrar tekrar kullandığından, birinin orada tamsayı olmayan bir şey veya geçersiz bir tamsayı ('-1' pil kullanır) takmasını da önleyemezsiniz.

Bu daha sonra ürün için bir model yazmaya çalışmanın etkileri vardır. Sen güzel Yazılan değerlere sahip olacak ... ama aynı zamanda bir zorunda gidiyoruz Map<String,String>sadece her türlü orada oturan şeyler onun içinde. Bu daha sonra, XML veya Json'a seri hale getirildiğinde ve bu yapılara karşı doğrulama veya sorgulama yapmaya çalışmanın karmaşıklığının yanı sıra başka etkileri de vardır .

Dikkate alınması gereken düzende bazı alternatifler veya modifikasyonlar, serbest formlu bir anahtar yerine, geçerli anahtarlarla başka bir tabloya sahip olmaktır. Veritabanında string karşılaştırması yapmak yerine, yabancı anahtar kimliklerinin eşitliğine karşı kontrol ettiğiniz anlamına gelir. Anahtarın değiştirilmesi bir noktada yapılır. Bilinen bir anahtar setiniz var, yani enum olarak kullanılabilecekleri var.

Belirli bir ürün sınıfının niteliklerini içeren ilgili tablolara da sahip olabilirsiniz. Bir bakkal departmanı, yapı malzemelerinin ihtiyaç duymadığı (ve bunun tersi) onunla ilişkili çeşitli özelliklere sahip başka bir masaya sahip olabilir.

+----------+    +--------+    +---------+
|Grocery   |    |Product |    |BuildMat |
|id (fk)   +--->|id (pk) |<---+id (fk)  |
|expiration|    |desc    |    |material |
|...       |    |img     |    |...      |
+----------+    |price   |    +---------+
                |...     |               
                +--------+               

Özellikle bir EAV tablosu için çağıran zamanlar vardır .

Her ürünü ve her bir özelliği bildiğiniz, şirketiniz için sadece bir envanter sistemi yazmadığınız durumu düşünün. Şimdi diğer şirketlere satmak için bir envanter sistemi yazıyorsunuz. Sen olamaz her ürünün her özniteliğini biliyorum - onları tanımlamak gerekir.

Çıkar Bir fikir "müşteri tabloyu değiştirmek izin vereceğim" dir ve bu (artık nerede ne olduğunu biliyor çünkü, tablo yapıları için meta-programlama içine ellerinden almak sadece kötü krallar pisliği yapı veya bozuk uygulama, yanlış şeyler yapma erişimine sahipler ve bu erişimin etkileri önemli hale geliyor). MVC4'te bu yol hakkında daha fazlası var : Çalışma zamanında model nasıl oluşturulur?

Bunun yerine, bir EAV tablosuna yönetici arabirimi oluşturun ve kullanılmasına izin verin. Müşteri 'polkadots' için bir giriş oluşturmak isterse, EAV tablosuna girer ve bununla nasıl baş edeceğinizi zaten bilirsiniz.

Bunun bir örneği Redmine veritabanı modelinde görülebilir , custom_fields tablosunu ve custom_values ​​tablosunu görebilirsiniz - bunlar EAV'nin sistemin genişletilmesine izin veren kısımlarıdır.


Tüm tablo yapınızı ilişkiselden ziyade EAV'ye benzeyecek şekilde bulursanız, NoSQL'in (cassandra, redis, Mongo, ...) KV lezzetine bakmak isteyebileceğinizi unutmayın. Bu genellikle ile gelen fark diğer sizin için kullanarak ne ya uygun olabilir veya olmayabilir onların tasarımında ödünleşmeler. Bununla birlikte, bir EAV yapısının amacı ile özel olarak tasarlanmıştır.

Bir envanter yönetimi sistemi için SQL - NoSQL okumak isteyebilirsiniz

Bu yaklaşımın ardından belge yönelimli bir NoSQL veritabanıyla (kanepe, mongo), her envanter öğesinin bir disk üzerinde bir belge olduğunu düşünebilirsiniz ... her şeyi tek bir belgede hızlıca çekerek. Ayrıca, belge tek bir şeyi hızlıca çıkarabilmeniz için yapılandırılmıştır. Öte yandan, tüm belgeleri belirli bir özellik ile eşleşen şeyler için aramak daha az performans gösterebilir (tüm dosyalara karşı 'grep' kullanarak karşılaştırın) ... hepsi değiş tokuş eder.

Diğer bir yaklaşım, birinin tüm ilişkili öğeleriyle bir temele sahip olacağı, ancak daha sonra diğer öğe türleri için kendisine uygulanan ilave nesne sınıflarına sahip olacağı LDAP olacaktır. (bkz . LDAP Kullanarak Sistem Envanteri )

Bu yollardan geçmeyi sonra, olabilecek aynen herşey bazı ödünleşmeler ile gelir gerçi sizin için ... aradıklarını eşleştiğini şey bulmak.


10

6 yıl sonra

Şimdi Postgres'teki JSON burada, Postgres kullananlar için başka bir seçeneğimiz var. Bir ürüne yalnızca bazı ekstra veriler eklemek istiyorsanız, ihtiyaçlarınız oldukça basittir. Örnek:

CREATE TABLE products (sku VARCHAR(30), shipping_weight REAL, detail JSON);
INSERT INTO products ('beachball', 1.0, '{"colors": ["red", "white"], "diameter": "50cm"}');

SELECT * FROM products;
    sku    | weight |               detail               
-----------+--------+------------------------------------
 beachball |      1 | {"colors": ["red", "white"], "diameter": "50cm"}

İşte Postgres'te JSON'a daha yumuşak bir giriş: https://www.compose.com/articles/is-postgresql-your-next-json-database/ .

Postgres'in aslında JSONB'yi sakladığını, düz metin JSON'unu saklayamadığını ve gerçekte bu verilere karşı sorgulamak istediğinizi saptamanız durumunda bir JSONB belgesinin / alanının içindeki alanlardaki dizinleri desteklediğini unutmayın.

Ayrıca, bir JSONB alanı içindeki alanların bir UPDATE sorgusu ile ayrı ayrı değiştirilemediğini unutmayın; JSONB alanının tüm içeriğini değiştirmeniz gerekecektir.

Bu cevap doğrudan soruyu çözmeyebilir, ancak orijinal soruyu düşünen herkes tarafından düşünülmesi gereken bir EAV düzenine bir alternatif sunar.


3
Alternatif bir çözüm yollamanın harika bir fikir olduğunu düşünüyorum. Diğerlerini izlemeye devam etmek için MS SQL, bir süre dizine ekleyebilme yeteneğine sahip XML sütunlarını destekliyordu ve 2016'dan başlayarak, JSON ile aynı şeyi yapabilir (JSON, MS SQL'de yerel bir sütun türü olmasa da, yine de dizine ekleyebilirsin. ). Öte yandan - okuduklarımdan sonra, Postgres JSON desteği daha iyi, örneğin JSON dizi özelliklerinde veriler üzerindeki dizinleri destekliyor gibi görünüyor.
Giedrius

1
"... bir JSONB alanındaki alanlar bir UPDATE sorgusu ile ayrı ayrı değiştirilemez; JSONB alanının tüm içeriğini değiştirmeniz gerekir." Bu modası geçmiş, değil mi? jsonb_set()Postgres 9.5 ve sonrasında tam olarak bunun için bir fonksiyon var . (Linklere bağladığın makale, 9.5 özellik
eklerini

7

Genelde insanlar arama tabloları için kullanıyorsanız ya da yararın bir ya da iki saklı değer için tablo oluşturmak zorunda kalmaması gereken diğer durumlar için kullanıyorlar. Tanımladığınız durum, temel olarak öğe özelliklerini sakladığınız yer, tamamen normal (ve normalleştirilmiş) sesler. Değişken sayıda öğe niteliği depolamak için bir tablonun genişletilmesi kötü bir fikirdir.

Genel olarak farklı verileri uzun ince bir tabloda depolamak için ... Gerekirse yeni tablolar oluşturmaktan korkmamalısınız ve yalnızca bir veya iki uzun sıska tabloya sahip olmak sadece bir veya iki kısa yağlı tablo.

Olduğu söyleniyor, günlükleme için EAV tabloları kullanmak için ünlüyüm. Bazı iyi yararları var.


Lütfen "sıska tablo" ve "yağ tablosu" tanımlayın.
Tulains Córdova

@ TulainsCórdova: "Sıska" bir tablo, birkaç satırdan ve birçok sütundan oluşuyor, şişman bir tablo ise birçok sütun ve birkaç satırdan oluşuyor. Bir örnek, kitaplar için söyleyeceğiniz özelliklere sahip bir arama tablosu oluşturmak olabilir. Bir şişman tablonun kitap başına bir kaydı olacak ve belirli veri parçaları için birçok sütuna sahip olacaktı. Birincinin avantajı, daha az sayıda kayıt bulunmasıdır, ancak olumsuz olanı, bazı alanların boş olması ve her şeyin genişletilmesi zor olmasıdır.
Satanicpuppy

@Satanicpuppy Ben sıska / yağ tanımları karışık olduğunu düşünüyorum - aynıdır. Sıska bir tablonun birkaç sütunu ve birçok satırı olduğunu mu demek istiyorsun?
Charles Wood,

1

EAV, açık yapı sorununu örtük algıya dönüştürür. X'in A ve B sütunlarına sahip bir tablo olduğunu söylemek yerine, A ve B sütunlarının X tablosunu oluşturduğunu ima edersiniz. Bir anlamda tam tersidir, ancak bire bir eşleme yoktur. Hem A hem de B'nin masaya (veya tip) X ve Y'ye eşlendiğini söyleyebilirsiniz. Bu, bağlamın önemli olduğu daha ilgili alanlarda önemli olabilir.

Bu tür bir yaklaşım için Datomic'i inceliyorum ve bence yapması gerekenleri (yapamayacağınızı değil) sınırlamaları olan çok kullanışlı ve güçlü bir sistem.

EAV'nin yavaş olacağı ya da "kendini asman için yeterli ipi ver", hemfikir olduğum bir açıklama değil. Aksine, EAV'nın güçlü yönlerine daha fazla önem verirdim ve eğer sorun alanınıza uyarsa, bunu düşünmelisiniz.

Benim deneyimim, bu modelleme için neredeyse sınırsız bir yaklaşım. Spesifik olarak, Datomik durumunda, her şeyin üstüne bir set semantik yüklerler. Bir ilişkiyi modelleyen herhangi bir modelleme kararı, sütunları / tabloları yeniden tasarlamak zorunda kalmadan birinden çoğuna serbestçe gidebilir. Kısıtlama değişmezliği ihlal etmediği sürece de geri dönebilirsiniz. Her şey kaputun altında aynı.

EAV ile ilgili sorun aklımda Datomic gibi bir uygulama eksikliği ile olmuştur. Bu EAV ile ilgili bir soru olduğu için Datomic hakkında övünmek istemiyorum ama EAV ile ilgili her şeyi doğru yaptıklarını düşündüğüm şeylerden biri.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.