Он называется Entity-Attribute-Value (также иногда «пары имя-значение») и является классическим случаем «круглого колышка в квадратном отверстии», когда люди используют шаблон EAV в реляционной базе данных.
Вот список того, почему вы не должны использовать EAV:
- Вы не можете использовать типы данных. Не имеет значения, является ли значение датой, числом или деньгами (десятичными). Это всегда будет принуждено к varchar. Это может быть что угодно, от незначительной проблемы с производительностью до огромной боли в кишечнике (когда-либо приходилось гоняться за отклонением в один цент в ежемесячном сводном отчете?).
- Вы не можете (легко) применять ограничения. Требуется смешной объем кода для обеспечения того, что «Каждый должен иметь высоту от 0 до 3 метров» или «Возраст должен быть не нулевым, а> = 0», в отличие от 1-2 строк, которые будут обозначать каждое из этих ограничений. в правильно смоделированной системе.
- В связи с вышесказанным, вы не можете легко гарантировать, что вы получаете необходимую информацию для каждого клиента (возраст может отсутствовать у одного, тогда у следующего может отсутствовать их рост и т. Д.). Вы можете сделать это, но это намного сложнее, чем
SELECT height, weight, age FROM Client where height is null or weight is null
.
- Еще раз, связанные с дублирующимися данными обнаружить намного сложнее (что произойдет, если они дадут вам два возраста для одного клиента? Удаление данных из EAV, как показано ниже, даст вам две строки результатов, если один атрибут удвоен. Если один клиент имеет две отдельные записи для двух атрибутов, вы получите четыре строки из запроса ниже).
- Вы даже не можете гарантировать, что имена атрибутов совпадают. "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"
Для того, чтобы:
SELECT c.ID, c.Ht_cm, c.Wt_kg, c.Age_yr
FROM Client c
Вот (очень короткий) список того, когда вы должны использовать EAV:
- Когда нет абсолютно никакого способа обойти это, и вам нужно поддерживать данные без схемы в вашей базе данных.
- Когда вам просто нужно хранить «вещи» и не ожидать, что они понадобятся в более структурированной форме. Остерегайтесь, однако, монстра под названием «изменяющиеся требования».
Я знаю , что я только что провел весь этот пост подробно , почему EAV страшная мысль в большинстве случаев - но там есть несколько случаев , когда это нужно / неизбежными. однако, в большинстве случаев (включая приведенный выше пример), это будет намного сложнее, чем стоит. Если у вас есть потребность в широкой поддержке ввода данных типа EAV, вам следует рассмотреть возможность их хранения в системе ключ-значение, например, Hadoop / HBase, CouchDB, MongoDB, Cassandra, BerkeleyDB.
Значение атрибута сущности (EAV)
Это считается анти-паттерном для многих, в том числе и для меня.
Вот ваши альтернативы:
использовать наследование таблицы базы данных
использовать данные XML и функции SQLXML
используйте базу данных nosql, такую как HBase
источник
В PostgreSQL очень хорошим способом работы со структурами EAV является дополнительный модуль
hstore
, доступный для версии 8.4 или новее. Я цитирую руководство:Начиная с Postgres 9.2 есть также
json
тип и множество функциональных возможностей ( большинство из них добавлено в 9.3 ).Postgres 9.4 добавляет (в основном превосходящий!) Тип данных «двоичный JSON»
jsonb
в список опций. С расширенными параметрами индекса.источник
Если у вас есть база данных, которая использует структуру EAV, можно запросить данные различными способами.
Ответ Саймона уже показывает, как выполнить запрос, используя несколько соединений.
Пример используемых данных:
Если вы используете СУБД, которая имеет
PIVOT
функцию ( SQL Server 2005+ / Oracle 11g + ), вы можете запросить данные следующим образом:Смотрите SQL Fiddle с демо
Если у вас нет доступа к
PIVOT
функции, вы можете использовать агрегатную функцию сCASE
оператором для возврата данных:Смотрите SQL Fiddle с демо
Оба этих запроса вернут данные в результате:
источник
Забавно видеть, как модель EAV db подвергается критике и даже рассматривается некоторыми как «анти-паттерн».
Насколько я понимаю, основные недостатки :
Однако вы не должны отказываться от этого решения, и вот почему:
источник