Есть ли название для этой структуры базы данных?

Мы обрабатываем обычную ленту данных от клиента, который просто реорганизовал свою базу данных из формы, которая кажется знакомой (по одной строке на сущность, по одному столбцу на атрибут) той, которая кажется мне незнакомой (по одной строке на объект за атрибут):

До: один столбец за атрибут

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

После: один столбец для всех атрибутов

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

Есть ли имя для этой структуры базы данных? Каковы относительные преимущества? Старому способу проще разместить ограничения на допустимость для определенных атрибутов (не нуль, неотрицательно и т. Д.) И проще вычислять средние значения. Но я вижу, как было бы проще добавлять новые атрибуты без рефакторинга базы данных. Является ли это стандартным /предпочтительным способом структурирования данных?

63 голоса | спросил prototype 12 J000000Thursday12 2012, 06:41:17

5 ответов


86

Он называется Entity-Attribute-Value (также иногда «пары имя-значение»), и это классический случай «круглой привязки в квадратной дыре», когда люди используют шаблон EAV в реляционной базе данных.

Вот список того, почему вы не должны использовать EAV:

  • Вы не можете использовать типы данных. Не имеет значения, является ли значение датой, числом или деньгами (десятичным). Его всегда будут принуждать к варчару. Это может быть что угодно: от незначительной проблемы с производительностью до массивной боли в кишечнике (когда-либо приходилось преследовать одноцентную вариацию ежемесячного сводного отчета?).
  • Вы не можете (легко) применять ограничения. Для этого требуется нелепое количество кода для обеспечения «Каждый должен иметь высоту между 0 и 3 метрами» или «Возраст должен быть не нулем и> = 0», в отличие от 1-2 строк, каждое из которых быть в правильно смоделированной системе.
  • В соответствии с вышеизложенным вы не можете легко гарантировать, что вы получите необходимую информацию для каждого клиента (возраст может отсутствовать в одном, а затем следующий может отсутствовать по высоте и т. д.). Вы можете сделать это, но это намного сложнее, чем SELECT height, weight, age FROM Client where height is null or weight is null.
  • Связанные снова повторяющиеся данные намного сложнее обнаружить (что происходит, если они дают вам два возраста для одного клиента? De-EAVing данных, как показано ниже, даст вам две строки результатов, если у вас есть один атрибут в два раза. Если один клиент имеет две отдельные записи для двух атрибутов, вы получите строки four из запроса ниже).
  • Вы даже не можете гарантировать, что имена атрибутов согласованы. «Age_yr» может стать «AGE_IN_YEARS» или «age». (По общему признанию, это не проблема, когда вы получаете экстракт по сравнению с тем, когда люди вставляют данные, но все же.)
  • Любой вид нетривиального запроса - полная катастрофа. Чтобы реляционировать трехэлементную систему EAV, чтобы вы могли запросить ее рациональным образом, требуется три объединения таблицы EAV.

Для сравнения:

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"

To:

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

Вот список (очень короткий), когда вы должны использовать EAV:

  • Если абсолютно нет, и вам нужно поддерживать без схемы данные в своей базе данных.
  • Когда вам просто нужно хранить «материал» и не ожидайте, что он понадобится в более структурированной форме. Остерегайтесь, однако, монстра, называемого «меняющимися требованиями».

Я знаю, что я просто провел весь этот пост, объясняя, почему EAV является ужасной идеей в большинстве случаев, но там есть несколько случаев, когда это необходимо /неизбежно. однако большую часть времени (включая пример выше), это будет намного сложнее, чем это стоит. Если у вас есть требование для широкой поддержки ввода данных типа EAV, вы должны посмотреть на их хранение в системе значений ключа, например. Hadoop /HBase, CouchDB, MongoDB, Cassandra, BerkeleyDB.

ответил Simon Righarts 12 J000000Thursday12 2012, 07:57:54
17

Значение атрибута сущности (EAV)

Считается, что это анти-шаблон многими, включая меня.

Вот ваши альтернативы:

  1. использовать базу данных наследование таблицы

  2. использовать XML-данные и функции SQLXML

  3. используйте базу данных nosql, такую ​​как HBase

ответил Neil McGuigan 12 J000000Thursday12 2012, 06:54:47
13

В PostgreSQL один очень хороший способ справиться с структурами EAV - это дополнительный модуль hstore , доступный для версии 8.4 или новее. Я цитирую руководство:

  

Этот модуль реализует тип данных hstore для хранения наборов   пары ключ /значение в пределах одного значения PostgreSQL. Это может быть полезно   в различных сценариях, таких как строки со многими атрибутами, которые   редко рассматриваемых или полуструктурированных данных. Ключи и значения просто   текстовые строки.

Так как Postgres 9.2 также есть json и множество функций для его работы ( большая часть из них добавлена ​​с 9.3 ).

Postgres 9.4 добавляет (в основном превосходящий!) тип данных «двоичный JSON» jsonb в список параметров. С расширенными опциями индекса.

ответил Erwin Brandstetter 13 22012vEurope/Moscow11bEurope/MoscowTue, 13 Nov 2012 14:25:46 +0400 2012, 14:25:46
9

Если у вас есть база данных, использующая структуру EAV, можно запросить данные различными способами.

@ Ответ Саймона уже показывает, как выполнить запрос, используя несколько соединений.

Используемые данные:

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

Если вы используете СУРБД с функцией PIVOT ( SQL Server 2005+ / Oracle 11g + ), тогда вы можете запросить данные следующим образом:

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;

См. SQL Fiddle with Demo

Если у вас нет доступа к функции PIVOT, вы можете использовать агрегированную функцию с оператором 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

См. SQL Fiddle with Demo

Оба этих запроса возвратят данные в результате:

| ID | HT_CM | WT_KG | AGE_YR |
-------------------------------
|  1 |   190 |    82 |     43 |
|  2 |   170 |    60 |     22 |
|  3 |   205 |    90 |     51 |
ответил Taryn 25 TueEurope/Moscow2012-12-25T02:24:00+04:00Europe/Moscow12bEurope/MoscowTue, 25 Dec 2012 02:24:00 +0400 2012, 02:24:00
8

Забавно видеть, как модель EAV db подвергается критике и даже рассматривается как «анти-шаблон».

Насколько мне известно, основные недостатки :

  • Кривая обучения более крутая , если вы попадаете в проект, который уже начал использовать EAV некоторое время назад. Действительно, запросы жесткие , поскольку вы значительно увеличиваете количество объединений (и таблиц), и это будет задайте больше времени, чтобы вы поняли. Просто взгляните на Magento проекта и посмотреть, как у разработчиков, внешних по отношению к проекту, трудное время работая над БД, но документация хорошо поддерживается.
  • Не подходит для сообщения , если вам нужно получить число людей, имя которых начинается с «M» и т. д.

Однако вы не должны отбрасывать это решение, и вот почему:

  • Саймон рассказал о монстре, который называется «меняющиеся требования». Мне нравится это выражение :). И IMHO именно поэтому EAV может быть хорошим кандидатом, потому что это хорошо подходит для «изменения» , так как вы можете добавить столько атрибутов, сколько хотите. Конечно, это зависит от требований, которые мы меняем. Если мы говорим о совершенно новом бизнесе, конечно, вам придется пересмотреть свой dataModel, но EAV предлагает большую гибкость. Просто потому, что он требует большей строгости, не означает, что это менее интересно.
  • Было также сказано, что «вы не можете использовать типы данных». : Это неверно . У вас может быть очень много таблиц значений , по одному для каждого типа данных. Затем вам нужно указать в таблице атрибутов, какой тип dataType является вашим атрибутом. Фактически, сочетание классического отношения /EAV с отношениями между классами дает много интересного в дизайне базы данных.
ответил Melvin PRESSOUYRE 7 Jam1000000amMon, 07 Jan 2013 03:25:38 +040013 2013, 03:25:38

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132