it-swarm-eu.dev

Existuje pro toto schéma databáze název klíčových hodnot?

Zpracováváme rutinní datový zdroj od klienta, který právě přeformuloval svou databázi z formuláře, který se zdá být známý (jeden řádek na entitu, jeden sloupec na atribut) do podoby, která se mi zdá neznámá (jeden řádek na entitu na atribut):

Před: jeden sloupec na atribut

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

After: jeden sloupec pro všechny atributy

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     ...

Existuje název této struktury databáze? Jaké jsou relativní výhody? Zdá se, že starý způsob je jednodušší umístit omezení platnosti na specifické atributy (nenulové, nezáporné atd.) A snáze vypočítat průměry. Ale vidím, jak může být snazší přidat nové atributy, aniž by došlo k refaktorizaci databáze. Je to standardní/preferovaný způsob strukturování dat?

70
prototype

Říká se tomu entita-atribut-hodnota (také někdy 'páry název-hodnota') a je to klasický případ „kulatého kolíku ve čtvercové díře“, když lidé používají vzor EAV v relační databázi.

Zde je seznam důvodů, proč byste neměli používat EAV:

  • Nelze použít datové typy. Nezáleží na tom, zda je hodnota datum, číslo nebo peníze (desetinné). Vždy bude nucen varchar. Může se jednat o něco od malého problému s výkonem až po masivní bolest střev (někdy musela pronásledovat jednu centovou variaci v měsíční souhrnné zprávě?).
  • Nemůžete (snadno) vynutit omezení. Vyžaduje směšné množství kódu k vynucení „Každý musí mít výšku mezi 0 a 3 metry“ nebo „Věk nesmí být nulový a> = 0“, na rozdíl od 1-2 řádků, které by každé z těchto omezení bylo. ve správně modelovaném systému.
  • Vzhledem k výše uvedenému nemůžete snadno zaručit, že získáte informace, které potřebujete pro každého klienta (věk může chybět od jednoho, poté u dalšího může chybět jeho výška atd.). Vy to dokážete , ale je to sakra mnohem obtížnější než SELECT height, weight, age FROM Client where height is null or weight is null.
  • Znovu související, duplicitní data je mnohem těžší detekovat (co se stane, pokud vám poskytnou dva věky pro jednoho klienta? De-EAVing data, jak je uvedeno níže, vám poskytne dva řádky výsledků, pokud máte jeden atribut zdvojnásobený. Pokud je jeden klient má dva samostatné záznamy pro dva atributy, z dotazu níže získáte čtyři řádky).
  • Nemůžete ani zaručit, že názvy atributů jsou konzistentní. „Age_yr“ může být „AGE_IN_YEARS“ nebo „age“. (Je pravda, že to není menší problém, když dostáváte výpis oproti tomu, kdy lidé vkládají data, ale přesto.)
  • Jakýkoli druh netriviálního dotazu je úplnou katastrofou. Chcete-li relaci systému EAV se třemi atributy, abyste jej mohli racionálně dotazovat, vyžaduje tři spojení tabulky EAV.

Porovnat:

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"

Na:

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

Zde je (velmi krátký) seznam, kdy byste měli používat EAV:

  • Pokud neexistuje absolutně , neexistuje žádná možnost a v databázi musíte podporovat data bez schématu.
  • Když stačí ukládat „věci“ a neočekáváte, že je budete potřebovat ve strukturovanější podobě. Pozor však na monstrum zvané „měnící se požadavky“.

Vím, že jsem právě strávil celý tento příspěvek podrobně, proč je EAV ve většině případů hrozný nápad - ale existuje několik případů, kdy je to nutné/nevyhnutelné. Většinu času (včetně výše uvedeného příkladu) však bude mnohem obtížnější, než stojí za to. Pokud máte požadavek na širokou podporu vstupu dat typu EAV, měli byste se podívat na jejich uložení v systému klíč-hodnota, např. Hadoop/HBase, CouchDB, MongoDB, Cassandra, BerkeleyDB.

95
Simon Righarts

Hodnota atributu entity (EAV)

Mnoho, včetně mě, je považováno za anti-vzor.

Zde jsou vaše alternativy:

  1. použijte databázi dědičnost tabulky

  2. použijte data XML a funkce SQLXML

  3. použijte databázi nosql, jako je HBase

19
Neil McGuigan

V PostgreSQL je velmi dobrým způsobem, jak se vypořádat se strukturami EAV, další modul hstore , dostupný pro verze 8.4 nebo novější. Cituji manuál:

Tento modul implementuje datový typ hstore pro ukládání sad párů klíč/hodnota v rámci jedné hodnoty PostgreSQL. To může být užitečné v různých scénářích, jako jsou řádky s mnoha atributy, které jsou zřídka zkoumány, nebo polostrukturovaná data. Klíče a hodnoty jsou jednoduše textové řetězce.

Od Postgresu 9.2 existuje také typ json a hostitel s funkcemi (- - většina z nich byla přidána s 9. ).

Postgres 9.4 přidává (převážně lepší!) Datový typ "binární JSON" jsonb do seznamu možnosti. S pokročilými možnostmi indexu.

16
Erwin Brandstetter

Je zvláštní vidět, jak je model EAV db kritizován a někteří dokonce považováni za „anti-model“.

Pokud jde o mě, hlavní nevýhody jsou:

  • Výuková křivka je strmější pokud se dostanete na projekt, který již začal používat EAV před nějakou dobou. Opravdu, dotazy jsou těžké, jak výrazně zvýšíte počet spojení (a tabulek), a tak si vyžádáte více času, abyste porozuměli. Stačí se podívat na projekt Magento a podívat se, jak má externí externí projekt těžkou práci na DB, přesto je dokumentace dobře udržovaná.
  • Nevhodné pro reportování, pokud potřebujete získat počet lidí, kteří se začali jmenovat „M“ atd ...

Toto řešení byste však rozhodně neměli zahodit, a zde je důvod:

  • Simon mluvil o monstra nazvané „měnící se požadavky“. Líbí se mi tento výraz :). A IMHO právě proto může být EAV dobrým kandidátem, protože je to vhodné pro „změnu“, protože můžete přidat tolik atributů, kolik si budete přát. Samozřejmě to záleží na požadavcích, které měníme. Pokud mluvíme o zcela novém podnikání, budete samozřejmě muset zkontrolovat dataModel, ale EAV nabízí velkou flexibilitu. To, že to vyžaduje přísnější, neznamená, že je to méně zajímavé.
  • Bylo také řečeno, že „nelze použít datové typy.“ : To je špatně. Můžete mít velmi dobře několik hodnotových tabulek, jednu pro každý typ dataType. Potom musíte v tabulce atributů určit, jaký druh dataType je vaším atributem. Ve skutečnosti kombinace klasického relačního/EAV s třídním vztahem nabízí v designu datové základny spoustu zajímavého potenciálu.
11

Pokud máte databázi používající strukturu EAV, je možné data dotazovat různými způsoby.

@ Simonova odpověď již ukazuje, jak provést dotaz pomocí více spojení.

Použitá vzorová data:

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);

Pokud používáte RDBMS, který má funkci PIVOT ( SQL Server 2005 + / Oracle 11g + ), můžete data dotazovat následujícím způsobem:

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;

Viz SQL Fiddle s Demo

Pokud nemáte přístup k funkci PIVOT, můžete pro vrácení dat použít agregační funkci s příkazem CASE:

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

Viz SQL Fiddle s Demo

Oba tyto dotazy vrátí data ve výsledku:

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