4 March 2019

Magento 2 EAV: обзор структур данных

Magento

В данной публикации я обзорно рассмотрю структуры данных Magento 2, поддерживающих функционирование такой концепции, как EAV. Разработчикам иногда нужно выбираться из дебрей кода и пытаться обозревать места своего жизнепровождения с высоты полёта орла — это позволяет наводить фокусы на вещи действительно важные или просто большие. Вот я и выбрался.


image


Аббревиатура EAV раскрывается как Entity-Attribute-Value (это для тех, кто не ходил по ссылке выше). Основной "плюшкой" EAV является эффективное использование пространства БД в тех случаях, когда возможное количество различных атрибутов (свойств, параметров), которые могут быть использованы для описания вещей (сущностей), является очень широким, но количество атрибутов, которое на самом деле относится к отдельному объекту, является относительно небольшим. Хорошим примером подобного случая в e-commerce служит такое понятие, как "продукт" — значимые атрибуты продуктов "телевизор" (размер экрана) отличаются от значимых атрибутов продуктов "спальный мешок" (минимальная комфортная температура).


Так что же Magento 2 предлагает для хранения данных в формате EAV?


'eav_' namespace


В свежеразвёрнутой базе Magento 2.3 есть 21 таблица с префиксом eav_. Все их можно разделить на три группы:


  • eav_attribute
  • eav_entity
  • eav_form

Проще всего с eav_form — эти таблицы относятся к отображению некоторых EAV-данных на UI и непосредственно к размещению EAV-данных в базе не относятся (я рассматриваю только структуры данных и только с точки зрения хранения информации, а не её отображения). Для эксперимента я удалил таблицы пространства eav_form из базы и это не помешало мне оформить заказ в магазине. Так что нужно ещё поискать, где используются данные из этого пространства таблиц и насколько они нужны для функционирования Magento.


Из оставшихся двух группа eav_attribute относятся к букве A(ttribute), а группа eav_entity — к букве E(ntity). Где же буква V(alue)?


Значения для атрибутов сущностей нужно искать в суффиксах имён таблиц:


  • _datetime
  • _decimal
  • _int
  • _text
  • _ varchar

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


  • catalog_category_entity_
  • catalog_product_entity_
  • customer_address_entity_
  • customer_entity_
  • eav_entity_

Простое перемножение кол-ва суффиксов (5) на кол-во префиксов (5) даёт нам общее кол-во таблиц (25) в которых предполагается хранение values-данных.


'eav_entity_type': реестр типов сущностей


Начало EAV в Magento нужно искать в таблице eav_entity_type. Именно здесь задаётся, для каких типов сущностей значения атрибутов будут сохранятся в EAV-структуре. Так вот, изначально Magento 2.3 предлагает такой вариант для следующих восьми сущностей:


  • customer
  • customer_address
  • catalog_category
  • catalog_product
  • order
  • invoice
  • creditmemo
  • shipment

'eav_attribute': реестр атрибутов


Следующий шаг — находим, какими атрибутами могут характеризоваться эти типы сущностей. Данная информация находится в таблице eav_attribute. Реестр атрибутов имеет замыкание на реестр типов сущностей по внешнему ключу (foreign key). В реестре атрибутов изначально 135 записей, принадлежащих 4 типам сущностей:


  • customer
  • customer_address
  • catalog_category
  • catalog_product


    О чём это говорит? Ну, хотя бы о том, что остальные типы сущностей:


  • order
  • invoice
  • creditmemo
  • shipment

не используют EAV-структуру для хранения данных. То есть, на каком-то этапе энтузиазм присутствовал и использование EAV планировалось для восьми типов сущностей, но по факту остановились на 4.


'eav_entity_': пространство-призрак


Пространство таблиц eav_entity напоминают китайские города-призраки — из 9 таблиц пространства данные содержатся только в двух:


  • eav_entity_type: это реестр типов сущностей, о которых я упоминал выше;
  • eav_entity_attribute: используется для упорядочивания атрибутов в группах (ближе к отображению данных, чем к их хранению); данная информация больше относится непосредственно к самим атрибутам, чем к сущностям (т.е., явно не из этого прихода — ей место в пространстве eav_attribute_ );

Остальные 7 таблиц — пусты:


  • eav_entity
  • eav_entity_datetime
  • eav_entity_decimal
  • eav_entity_int
  • eav_entity_store
  • eav_entity_text
  • eav_entity_varchar

Очень похоже на попытку унификации способа хранения значений для атрибутов сущностей в одном наборе таблиц (datetime, decimal, int, text, varchar) вместо того, чтобы иметь по 5 таблиц с соответствующими суффиксами для каждого типа сущностей. На неудачную попытку? Или это будущее EAV в Magento?


image


По-любому, Земля же была безвидна и пуста, и тьма над бездною, и Дух Божий в настоящем эти таблицы изначально не используются.


Типы значений атрибутов


В таблице eav_entity_type задаются типы сущностей, в таблице eav_attribute задаются сами атрибуты и их привязка к соответствующим типам сущностей. А как определить, где искать значение для такого-то атрибута такой-то сущности?


В этом нам поможет поле eav_attribute.backend_type. Оно показывает, где сохраняются значения атрибутов:


  • static: в таблице с данными о самой сущности (например, значения для атрибута #9 — customer.email, нужно искать в таблице клиентов customer_entity в столбце email);

Для остальных типов значения сохраняются в отдельных таблицах, в названиях которых префикс соответствует типу сущности (customer_, ...) а суффикс — одному из типов данных:


  • datetime
  • decimal
  • int
  • text
  • varchar

Т.е., значения для атрибута #79 catalog_product.special_from_date типа datetime сохраняются в таблице catalog_product_entity_datetime. Значения для атрибута #77 catalog_product.price — в таблице catalog_product_entity_decimal.


Что можно интересного увидеть в таблице eav_attribute в связи с типами значений? Как я уже отмечал выше, в данной таблице описаны атрибуты только для 4 типов сущностей из 8, зарегистрированных в eav_entity_type. При этом для сущностей типа customer и customer_address все атрибуты, определённые изначально, имеют тип значений static — т.е., являются обычными колонками в таблице и никак не используют преимуществ EAV-подхода. Таблицы:


  • customer_entity_datetime
  • customer_entity_decimal
  • customer_entity_int
  • customer_entity_text
  • customer_entity_varchar
  • customer_address_entity_datetime
  • customer_address_entity_decimal
  • customer_address_entity_int
  • customer_address_entity_text
  • customer_address_entity_varchar

изначально пусты и могут быть использованы только программным путём (т.е., через админку, без сторонних расширений, нет возможности записать что-либо в эти таблицы).


EAV для категорий


Категории каталога — вот первая сущность, которая более-менее использует EAV подход в Magento. Тип сущности — catalog_category, всего изначальных атрибутов — 30, из которых не-статических — 26. То есть, значения только 4 атрибутов (children_count, level, path, position) сохраняются в таблице catalog_category_entity, остальные сохраняются в наборе таблиц catalog_category_entity_ [ datetime | decimal | int | text | varchar ].


Структура таблиц из этого набора очень похожа как друг на друга, так и на аналогичные таблицы других типов сущностей (клиентов, их адресов и т.д.):


CREATE TABLE `catalog_category_entity_datetime` (
  `value_id` int(11) NOT NULL AUTO_INCREMENT,
  `attribute_id` smallint(5) unsigned NOT NULL DEFAULT '0',
  `store_id` smallint(5) unsigned NOT NULL DEFAULT '0',
  `entity_id` int(10) unsigned NOT NULL DEFAULT '0',
  `value` datetime DEFAULT NULL,
  PRIMARY KEY (`value_id`),
  UNIQUE KEY `...` (`entity_id`,`attribute_id`,`store_id`),
  ...
) ...

Для различных типов сохраняемых значений (datetime, decimal, int, text, varchar) меняется только тип колонки value. Данная структура позволяет сохранять отдельное значение (value) отдельного атрибута (attribute_id) отдельной сущности (entity_id) для отдельной витрины (store_id).


В связи с архитектурными особенностями Magento добавляется дополнительная связь с витриной — store_id. Таким образом возможна локализация значений одного и того же атрибута одной и той же сущности для различных витрин. Категории каталога — это первые сущности в Magento, для которых можно использовать EAV-подсистему прямо "из коробки". Задавать значения для атрибутов каталогов можно через админку.


image


Можно не только давать различные значения для текстовых атрибутов, переводя на язык соответствующей витрины, но и локализовывать атрибуты других типов. Например, в преддверии рождественских праздников на ru-витринах магазина для атрибута catalog_category.custom_design_from можно выставить значения 7-го января следующего года, а на en-витринах — 24-го декабря этого.


image


EAV для продуктов


В общем-то, это тот самый тип сущностей, ради которого EAV и затевалась в Magento. Тип сущности — catalog_product, всего изначальных атрибутов — 63, из которых не-статических — 56. Структура таблиц, поддерживающих EAV для продуктов, аналогична структуре таблиц для каталогов. Но есть одно значительное отличие. Для продуктов можно создавать новые атрибуты через админку — это default'овый функционал Magento, из коробки. Если для других сущностей Magento предоставляет только EAV структуры данных в расчёте на их программное заполнение, то для продуктов реализован интерфейс, позволяющий делать это на уровне пользователя (управляющего магазином) — Stores / Attributes / Product.


Для продуктов задействованы ещё две таблицы, относящиеся к EAV:


  • eav_attribute_set
  • eav_attribute_group

По-большому счёту, они скорее относятся к отображению информации, чем к её хранению. Атрибуты продукта объединяются в наборы (set) и при создании продукта ему присваивается набор атрибутов, что позволяет при заполнении карточки продукта для, например, телевизора, выбирать набор атрибутов, относящийся именно к бытовой технике (или даже для группы продуктов "телевизоры"). Объединение атрибутов в наборы происходит в Stores / Attributes / Product / Attribute Set:


image


Итого


IMHO, Magento является хорошим примером того, что целесообразность применения EAV достаточно узкая. При закладке на использование EAV для 8 сущностей (eav_entity_type) EAV-нотация используется только для 4 сущностей (eav_attribute), из которых только 2 сущности имеют действительно EAV-атрибуты — catalog_category и catalog_product. Причём для catalog_category EAV-атрибуты используются не по своему прямому назначению (большое количество различных атрибутов для описания сущности при малом количестве атрибутов, относящихся к отдельному экземпляру), а для "по-витринной локализации" значений атрибутов (один и тот же набор атрибутов для сущности "категория каталога" с возможностью атрибута экземпляра иметь различные значения для различных витрин магазина).


Полноценное использование EAV применяется только для catalog_product (правда и тут есть примесь "по-витринной локализации", но это уже расширение EAV-модели, а не её профанация, как в случае с категориями). Зато с продуктами Magento раскрывает EAV по полной — Magento-приложение можно смело использовать для наглядной демонстрации принципов EAV.

Tags:magento 2entity-attribute-valuedatabase design
Hubs: Magento
+6
6.4k 17
Comments 4