Anahtar değerlerin bu veritabanı şeması için bir isim var mı?


68

Veritabanını, tanıdık gelen bir formdan (varlık başına bir satır, özellik başına bir sütun), bana yabancı gelen (özellik başına bir satır) tanıdık gelen bir formdan yeniden inceleyen bir müşteriden gelen rutin bir veri akışını işleriz:

Önce: özellik başına bir sütun

ID   Ht_cm   wt_kg   Age_yr  ... 
1      190      82     43    ...
2      170      60     22    ...
3      205      90     51    ...

Sonra: tüm özellikler için bir sütun

ID    Metric   Value
 1     Ht_cm     190
 1     Wt_kg     82
 1     Age_yr    43
 1      ...
 2     Ht_cm     170
 2     Wt_kg     60
 2     Age_yr    22
 2     ...
 3     Ht_cm     205
 3     Wt_kg     90
 3     Age_yr    51
 3     ...

Bu veritabanı yapısı için bir isim var mı? Nispi avantajlar nelerdir? Eski yöntem, geçerlilik kısıtlamalarını belirli özelliklere (boş olmayan, negatif olmayan vb.) Yerleştirmek ve ortalamaları hesaplamak için daha kolay görünür. Ancak, veritabanını yeniden yansıtmadan yeni özellikler eklemenin daha kolay olabileceğini görebiliyorum. Bu standart / tercih edilen bir veri yapılandırma yöntemi midir?

Yanıtlar:


91

Buna Varlık-Nitelik Değeri (bazen 'ad-değer çiftleri' de denir) denir ve insanlar EAV desenini ilişkisel bir veritabanında kullandıklarında klasik bir "kare delikli yuvarlak kazık" durumudur.

İşte neden EAV kullanmamanız gerektiğine dair bir liste :

  • Veri türlerini kullanamazsınız. Değerin tarih, sayı veya para olması önemli değildir (ondalık). Her zaman varchar'a zorlanacak. Bu, küçük bir performans probleminden büyük bir bağırsak ağrısına kadar herhangi bir şey olabilir (aylık toplama raporunda hiç bir kuruşluk bir değişimi kovalamak zorunda kalmadı mı?).
  • Kısıtlamaları (kolayca) uygulayamazsınız. Bu sınırlamaların her birinin alacağı 1-2 çizginin aksine, "Herkes 0 ile 3 metre arasında bir yüksekliğe sahip olmalı" veya "Yaş boş olmamalıdır ve> = 0" ı uygulamak için çok miktarda bir kod gerektirir. düzgün modellenen bir sistemde.
  • Yukarıdakilerle ilgili olarak, her bir müşteri için ihtiyaç duyduğunuz bilgileri almayı garanti edemezsiniz (yaş birinden eksik, sonra bir sonraki boyunda eksik olabilir). Sen olabilir bunu ancak daha zor bir fazlabirşey var SELECT height, weight, age FROM Client where height is null or weight is null.
  • Yine ilgili olarak, yinelenen verilerin algılanması çok daha zordur (bir müşteri için size iki yaş verirlerse ne olur? Aşağıdaki gibi, verilerin DİNİ ÇIKARILMASI, bir özellik iki katına çıktığında size iki sonuç satırı verir. iki özellik için iki ayrı giriş varsa , aşağıdaki sorgudan dört satır alırsınız ).
  • Öznitelik adlarının tutarlı olduğunu bile garanti edemezsiniz. "Age_yr", "AGE_IN_YEARS" veya "yaş" olabilir. (Kuşkusuz ki, insanlar veri eklerken buna karşı bir özü alırken bu daha az problemdir.)
  • Her türlü önemsiz sorgulama tam bir felakettir. Üç-özellikli bir EAV sistemini ilişkisel hale getirmek için rasyonel bir şekilde sorgulayabilmeniz için EAV tablosunun üç birleşimini gerektirir.

Karşılaştırmak:

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"

Kime:

SELECT c.ID, c.Ht_cm, c.Wt_kg, c.Age_yr
FROM Client c

EAV'yi ne zaman kullanmanız gerektiğine dair (çok kısa) bir liste:

  • Olmadığı zaman kesinlikle etrafında hiçbir şekilde ve veritabanınızda şema daha az veri desteklemek zorunda.
  • Sadece "eşyaları" saklamanız gerektiğinde ve daha yapılandırılmış bir şekilde buna ihtiyaç duymayı beklemiyorsanız. Yine de, “değişen gereksinimler” olarak adlandırılan canavara dikkat edin.

Ben EAV çoğu durumda çok kötü bir fikir Sadece neden detaylandırma tüm bu yazı harcanan biliyorum - ama orada olan o / kaçınılmaz ihtiyaç duyulan birkaç durum. ancak, çoğu zaman (yukarıdaki örnek dahil), değerinden çok daha fazla güçlük çekecek. EAV tipi veri girişinin geniş desteklenmesi için bir gereksiniminiz varsa, bunları anahtar-değer sisteminde (örn. Hadoop / HBase, CouchDB, MongoDB, Cassandra, BerkeleyDB) saklamaya dikkat etmelisiniz.


7
Küçük bir bildirimle +1: farklı türlerin değerlerini farklı tablolara yerleştirirseniz veri türlerini kullanabilirsiniz (peki, klasik EAV değil, bir tür iyileştirme). (Ama sonra ek bir soru geliyor: yeni bir öznitelik türünü nasıl biliyorsunuz?)
dezso

4
Kabul, ancak EAV'ın sisteminizle anlamsal olarak alakasız olan şeylerin bir listesini tutarken kullanmak için de iyi bir yaklaşım olduğunu ekleyeceğim. Örneğin, ürün özelliklerinin saklanması ve listelenmesi gereken bir çevrimiçi ürün kataloğu. Yeterli olmak için bir anahtar / değer çiftleri listeniz var, ancak sistem aslında bu anahtarların veya değerlerin ne hakkında olduğunu bilmiyor veya önemsemiyor. Bu durumda, EAV tehlikeleri önemsizdir.
Joel Brown

10
@JoelBrown ŞİMDİ umrunda değilsiniz, ancak yolun aşağısında bir VP katalogda ne kadar gömlek olduğunu, ister kahverengi düğmelerin ne de yaka düğmelerini bilmesini isterse, yazmak için bir sorgu orospu olacak. EAV normalde planlama veya öngörü eksikliği olduğunu gösterir.
JNK,

2
@JoelBrown (Çok küçük, çok dar) kullanımına sahip olduğunu kabul etmiyorum. Ancak eğer bilgi herhangi bir yapılandırılmış şekilde sorgulanacaksa, muhtemelen EAV
JNK'da

4
@JoelBrown İş gereksinimleriniz veya sakladığınız veriler değişirse, veri modeliniz de olmalıdır . Veri modeliniz taştan oyulmamalıdır. Ayrıca, ilişkisel bir veritabanı için, insanların EAV kullandıklarının zamanlarının% 99'u, bildiğim tüm veritabanı modellerini ve modellerini göz önünde bulundurmak yerine, "verilerimi nasıl saklayacağımı düşünmek için zaman harcamak istemiyorum" anlamına geliyor. EAV bu veri kümesi için en iyi sonucu veriyor ". Tekrarlamak için - orada olan EAV kullanışlı (ve belki de 'doğru' yanıt) olduğu durumlar, ancak seyrek konum.
Simon Righarts,


16

PostgreSQL'de, EAV yapılarıyla başa çıkmanın çok iyi bir yolu hstore, 8.4 veya daha sonraki sürümler için kullanılabilen ek modüldür . Kılavuzdan alıntı yapıyorum:

Bu modül, hstoretek bir PostgreSQL değerinde anahtar / değer çiftleri kümelerini depolamak için veri türünü uygular . Bu, nadiren incelenen birçok özelliğe sahip satırlar veya yarı yapılandırılmış veriler gibi çeşitli senaryolarda faydalı olabilir. Anahtarlar ve değerler sadece metin dizeleridir.

Postgres 9.2’den bu yana, jsonberaberinde kullanacağınız bir tür işlev ve işlevsellik de vardır ( çoğu 9.3 ile eklenmiştir ).

Postgres 9.4, (büyük ölçüde üstün!) "İkili JSON" veri türünü jsonbseçenekler listesine ekler . Gelişmiş dizin seçenekleri ile.


10

EAV yapısını kullanan bir veritabanınız varsa, verileri çeşitli yollarla sorgulamak mümkündür.

@ Simon'ın cevabı çoktan birleştirme kullanarak bir sorgulamanın nasıl yapıldığını zaten gösteriyor.

Kullanılan Örnek Veriler:

CREATE TABLE yourtable ([ID] int, [Metric] varchar(6), [Value] int);

INSERT INTO yourtable ([ID], [Metric], [Value])
VALUES (1, 'Ht_cm', 190),
    (1, 'Wt_kg', 82),
    (1, 'Age_yr', 43),
    (2, 'Ht_cm', 170),
    (2, 'Wt_kg', 60),
    (2, 'Age_yr', 22),
    (3, 'Ht_cm', 205),
    (3, 'Wt_kg', 90),
    (3, 'Age_yr', 51);

Bir PIVOTişlevi olan bir RDBMS kullanıyorsanız ( SQL Server 2005+ / Oracle 11g + ), verileri aşağıdaki şekilde sorgulayabilirsiniz:

select id, Ht_cm, Wt_kg, Age_yr
from
(
  select id, metric, value
  from yourtable
) src
pivot
(
  max(value)
  for metric in (Ht_cm, Wt_kg, Age_yr)
) piv;

Demo ile SQL Fiddle'ı görün

Bir PIVOTişleve erişiminiz yoksa CASE, verileri döndürmek için bir deyim içeren bir toplama işlevini kullanabilirsiniz :

select id,
  max(case when metric ='Ht_cm' then value else null end) Ht_cm,
  max(case when metric ='Wt_kg' then value else null end) Wt_kg,
  max(case when metric ='Age_yr' then value else null end) Age_yr
from yourtable
group by id

Demo ile SQL Fiddle'ı görün

Bu sorguların her ikisi de sonuçta veri döndürür:

| ID | HT_CM | WT_KG | AGE_YR |
-------------------------------
|  1 |   190 |    82 |     43 |
|  2 |   170 |    60 |     22 |
|  3 |   205 |    90 |     51 |

10

EAV db modelinin nasıl eleştirildiğini ve hatta bazıları tarafından "anti-patern" olarak değerlendirildiğini görmek komik.

Endişelendiğim kadarıyla, ana dezavantajları :

  • Bir süre önce EAV kullanmaya başlamış bir projeye başlarsanız öğrenme eğrisi daha diktir . Gerçekten de, katılım sayısını (ve masaları) büyük ölçüde arttırdığınız için sorgular oldukça zordur ve bu nedenle anlamanız için daha fazla zaman isteyecektir. Sadece Magento projesine bir göz atın ve projeye dışardan gelen devin DB üzerinde çalışma konusunda ne kadar zor zamanlar geçirdiğini görün, ancak belgeler iyi durumda.
  • Raporlama için uygun değil , adı "M" vb. Olan kişi sayısını almanız gerekiyorsa ...

Ancak, kesinlikle bu çözümü atmamalısınız ve işte bu yüzden:

  • Simon , "değişen gereksinimler" olarak adlandırılan canavardan bahsetti . Bu ifadeyi beğendim :). Ve IMHO bu tam olarak EAV'nin iyi bir aday olabileceğinin nedenidir, çünkü bu "değişim" için çok uygundur , çünkü istediğiniz kadar çok özellik ekleyebilirsiniz. Tabii ki değişmekte olduğumuz şartlara bağlı. Eğer yepyeni bir işletmeden bahsediyorsak, elbette verilerinizi gözden geçirmeniz gerekecek, ancak EAV çok fazla esneklik sunuyor. Sadece daha fazla titizlik istediği için, bunun daha az ilginç olduğu anlamına gelmez.
  • Aynı zamanda “Veri türlerini kullanamazsınız” denildi. : Bu yanlış . Her dataType için bir tane olmak üzere birkaç değer tablosuna sahip olabilirsiniz . Öznitelik tablosunda, hangi tür dataType'ın özniteliğiniz olduğunu belirtmeniz gerekir. Aslında, klasik ilişkisel / EAV ile sınıf ilişkisinin bir karışımı, dataBase tasarımında birçok ilginç potansiyel sunmaktadır.

2
Öğrenme eğrisi, karşılaştığı ilk EAV tasarımı için daha diktir. Ondan sonra hepsi birbirine benziyor.
ypercubeᵀᴹ

1
Geçici Yorum: Neden "raporlama için uygun değil" iddiasını anlamıyorum. EAV raporlama için harika görünüyor. Eav.values ​​adresinden ObjectId öğesini seçin; burada propertyId = name ve 'm%' gibi değer. Sanal şemadaki değişiklikler (örneğin, özellikler ekleme), yeniden derleme yapmak zorunda kalmadan herhangi bir dinamik raporlama arayüzüne (açılır pencereler gibi) dahil edilebilir.
crokusek
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.