Официальным языком
EAV (Entity-Attribute-Value, Сущность-Атрибут-Значение) - модель данных, в котором данные и метаданные хранятся в одном линейном списке.
В модели EAV сущность описывается набором атрибутов. Атрибуты, которые позволяют определять связи между сущностями, называются свойствами сущностей. Модель EAV, поддерживающая свойства, принято называть EAV/CR. Каждый атрибут понятия описывается набором характеристик
Модель EAV позволяет представить сущность в качестве абстрактного понятия, которое может содержать неограниченный набор атрибутов для задания простых или составных значений различных типов данных. В рамках модели EAV добавление новых понятий не влечет за собой изменение состава и структуры таблиц базы данных, создавать новые понятия, так же как определять и изменять состав их атрибутов, можно автоматизировано, и, главное, на любом этапе жизненного цикла системы
Для пояснения модели EAV в простом виде представим понятие в реляционной базе данных и в модели EAV. Реляционная модель описывает одно понятие как:
Модель EAV описывает одно понятие как:
Т.е. при описании сущности в СУБД самым простым образом может быть использована всего 1 таблица:
Такой подход позволяет пользователям (операторам данных) вводить не только значения атрибутов, но и подразумевает, что и наименования таких атрибутов будут введены оператором. Помимо прочего, такой подход нарушает базовые принципы хранения информации в РСУБД - как минимум наименования атрибутов должны быть идентичными для каждого набора значений каждого типа сущности, чтобы при получении данных из таблицы не возникало проблем когда одной характеристике могут соответствовать несколько атрибутов. Такая характеристика сущности как "Цвет" может быть введена следующим образом - "Цвет", "цвет", "цвет "(пробел в конце) или "ЦBЕТ"(латинская буква B при обозначении имени атрибута). Так же пользователям необходимо каждый раз вводить наименование одного и того же атрибута для разных сущностей. Решается эта проблема созданием:
- Договоренностей, при которых правильность ввода наименований будет контролироваться не с помощью программных логических условий, а с помощью нормативно-правовых актов - назовём это уровнем НПА
- Ограничений на стороне клиентского ПО (select distinct attributeName from SimpleEAVTable - при формировании автоматической подсказки как вариант решения) - назовём это уровнем логических условий или уровнем ЛУС
В первом случае всё сведётся к регулярному изданию/переизданию НПА, содержащих в себе описания договоренностей, которые будут регулярно изменяться в связи с добавлением новых атрибутов для описания новых характеристик.
Во втором же случае длительность выполнения запроса будет увеличиваться при описании в таблице все новых и новых сущности.
Решением возникающих проблем является подход, при котором (в общем случае) для организации структуры хранения данных модели EAV на физическом уровне в реляционной базе данных достаточно иметь всего три таблицы – таблицу, описывающую сущности, таблицу, описывающую атрибуты, и таблицу, содержащую непосредственно значения атрибутов. При этом таблица атрибутов содержит ссылку на идентификатор понятия из таблицы понятий, а таблица значений содержит ссылки на идентификатор атрибута, позволяя, таким образом, определить к какому понятию относятся те или иные значения
Тем не менее, у такого подхода есть свой недостаток - значения атрибутов могут хранится только в одном типе значений - типе, которому соответствует тип поля Value. Из схемы выше видно, что все числовые, логические, временные и идентификационные значения при добавлении в таблицу Values необходимо будет привести к единому типу text. А при получении и обработке данных необходимо будет проводить обратную операцию. Помимо дополнительной сложности, при которой операции выполняются конвертации регулярно выполняются и в одну сторону и в обратную, существует далеко ненулевая вероятность, что при одном из шагов при конвертировании сведений что-то пойдёт не так (дата введена в некорректном формате, вместо запятой в десятичном делителе используется точка или наоборот и т.д.)
Есть решения, позволяющие хранить в поле Value значения в формате JSON. Есть даже решения, которые позволяют реализовать хранение всех сущностей, атрибутов и значений в одной таблице (https://habr.com/ru/articles/475178/ - как пример). Тем не менее, не все РСУБД используемые для учёта данных, поддерживают тип JSON в качестве типа поля или поиск по полям, которые содержат JSON в качестве обычного текста. И вопрос не в выборе СУБД, а в версии уже используемой или купленной ранее.
Если отбросить решения с помощью JSON и сфокусироваться на принципе нормализации данных, то есть два общих способа решения указанного недостатка:
Первый способ разделяет значения между полями в зависимости от выбранного типа при создании атрибута
Второй способ разделяет значения между таблицами в зависимости от выбранного типа при создании атрибута
Таким образом любой из выбранных способов решает проблемы с именами атрибута и регулярной конвертацией значений из одного типа в другой не на уровнях НПА или ЛУС, а на уровне СУБД - не получится у пользователя или неосмотрительного программиста ввести значение "Два с половиной", в поле таблицы, которое ожидает "2,5" в качестве значения.
Возникает новая проблема, которую не сложно решить на уровне клиентского ПО, но не упомянуть её будет неправильно - соблюдение целостности данных.
Предположим, что каждая сущность, описываемая оператором в таблицах должна иметь характеристику "Цвет". При обычном подходе без использования EAV модели не сложно добавить поле "Color" и запретить ввод пустых значений - таким образом мы создадим ограничение на уровне РСУБД.
В EAV модели такое ограничение на уровне СУБД создать нельзя, но можно на уровне клиентского ПО при валидации вводимых данных указать обязательность ввода данных для указанного атрибута.
Ещё одной серьёзной проблемой указанной модели является сложность при построении запросов.
Для получения конкретного списка значений из такой структуры необходимо потратить больше времени на написание запроса, чем при получении такого же списка значений и привычной всем структуры.
Для тестового примера возьмём в качестве сущности торт. Теперь торт - уже не торт, а сущность с набором определенных характеристик. В примере нас интересует его вес, дата производства и сорт (ничего другого более простого в голову не пришло). Использовать будем SQLite в качестве РСУБД.
Ориентируясь на стандартные подходы к хранению данных таблица Cakes будет иметь основной идентификатор записи, по которому можно будет строить внешние связи, а так же значения характеристик, которые нас интересуют в рамках примера. Назовем эту структуру - А
Для отражения этой же сущности с помощью EAV используем структуру, которая позволяет хранить все значения атрибутов в одной таблице
А эту структуру, которая позволяет отразить в БД характеристики торта назовем - Б.
Учитывать в этих структурах мы будем только торты одной марки, названия и рецептуры - все они между собой различаются только весом, датой производства и сортом. Никакие другие сущности в эти структуры попадать не будут.
Для того, чтобы добавить строку в структуру А необходим только одна команда
То же самое - простой select - если нам необходимо получить характеристики добавленной строки
А вот теперь проделаем те же операции, используя структуру Б.
Скрипт вставки первого торта будет выглядеть следующим образом
Само собой, что при следующих вставках создавать атрибуты не требуется, но это в любом случае больше строк кода, чем при вставке записи структуру А.
А получить данные можно так:
Отсюда можно сделать вывод, что для получения данных в одинаковом виде из структуры Б требуется больше усилий, чем из структуры А. И чем больше таких характеристик надо вывести, тем больше усилий надо приложить.
Из вышесказанного примера закономерно сделать вывод, что запрос из структуры А будет выполняться гораздо быстрее, чем запрос из структуры Б при прочих равных вводных (количество данных, наличие индексов и т.д.)
Подведём итог первой части
Преимущества EAV
- Сущность представлена в качестве абстрактного понятия, которая может содержать неограниченный набор атрибутов для задания простых или составных значений различных типов данных
- Единый способ хранения всех данных
- Добавление новых сущностей или атрибутов не влечет за собой изменение состава и структуры таблиц базы данных
Недостатки EAV
- Сложности при соблюдении целостности данных
- Сложности при построении запросов
- Низкая производительность при построении запросов
Ссылки(для расширения понимания)
- Эффективные методы работы с вертикальной моделью данных (https://e-campus.vvsu.ru/files/695D0E68-613F-47C3-AEC7-CF4E7CC104F0.pdf
- International Journal of Computer Science and Software Engineering (http://ijcsse.org/published/volume8/issue7/p3-V8I7.pdf)