Структура таблиц для каталога товаров интернет-магазина

В данном обзоре будет четыре, если так можно выразиться, архитектурных паттерна для построения базы данных интернет-магазина. Структура будет затрагивать лишь каталог товаров и речь пойдёт в целом об архитектуре, не делая акцента на какой-либо конкретной СУБД, хотя если примеры запросов встретятся, то они будут на основе MySQL. Стоит также учитывать, что у каждой СУБД может быть своя реализация каких-либо решений, отсутствующая в других СУБД.

Возьмём за основу абстрактный интернет-магазин со множеством товаров от ноутбуков и стиральных машин до кофемолок. У каждого типа товара будет свой набор свойств (атрибутов или характеристик). Естественно, что у пользователя должна быть возможность сортировать и фильтровать товары по их свойствам, например по цене, весу, высоте, ширине, мощности и пр. (яркий пример: Яндекс.Маркет – система выбора разнообразных товаров).

Пример.

Интернет-Магазин продаёт комплектующие к ПК (жёсткие диски, оперативную память, видео карты и т.д). Очевидно, что для каждого типа будет индивидуальный набор характеристик, а для некоторых характеристики будут совпадать. Так, например, у жёстких дисков будет следующий набор атрибутов: интерфейс, буфер, скорость вращения шпинделя. Для оперативной памяти он будет несколько иной: тип памяти, тактовая частота, объём. Но для всех типов товаров будут также и общие характеристики, такие как: наличие на складе, цена и производитель.

С какой основной проблемой мы встретимся? Клиент (он же заказчик интернет магазина) хочет, чтобы у него был по максимуму гибко настраиваемый каталог товаров. Т.е., если вдруг, клиент начнёт продавать фотоаппараты, то, очевидно, он не захочет снова нанимать для этого программистов. И это желание вполне закономерно. Заказчик должен просто зайти в админ-панель, создать новый тип товара “Фотоаппараты”, задать для этого типа набор своих характеристик и всё – товар готов к продаже в интернет-магазине. Вот эту гибкость нам и нужно реализовать.

Постараемся рассмотреть если не все варианты реализации, то самые основные и ходовые. Ну и, как обычно, плюсы-минусы и вывод.

  1. EAV
  2. One table
  3. Flat tables
  4. Документо-ориентированная база данных

1. EAV EAV расшифровывается как Entity–attribute–value или по-русски: объект-атрибут-значение. Она представляет собой модель данных для описания сущностей, в которых количество атрибутов (свойств, параметров) может быть потенциально большим. Entity – это своего рода “элемент данных”, например, категории товаров или сам товар. Attribute – это атрибуты товара, например: название, описание, цена и так для каждого из типов товаров. И value представляет собой реальное значение, принадлежащее атрибуту. Упрощенная схема БД будет выглядеть следующим образом: Схема EAV ProductEntity – таблица описывающая сущности. ProductAttribute – таблица описывающая атрибуты сущностей. AttributeValue – таблица, содержащая значения атрибутов.

Данное решение позволяет довольно легко и непринуждённо изменять (добавлять, удалять или редактировать) набор параметров сущности.

Но очевидны и недостатки: значением атрибута будет являться только строковый тип, в нашем случае – это text, из этого следует то, что придётся преобразовывать типы. К тому же, работа со строками медленнее и затратнее в БД. Помимо этого, у нас могут появиться повторы для названий атрибутов.

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

Пример:

Структура EAV Т.о. значения атрибутов у нас будут хранится в отдельных таблицах значений, причём разбиты они будут по типам, т.е. атрибуты со строковыми значениями будут хранится в таблице строковых атрибутов, а значения атрибутов с целыми числами – будут храниться в таблице с целочисленными значениями атрибутов и т.д.

Минусы: сложные и ресурсоёмкие запросы к таблицам отсюда тормоза, причём, если без кеширования и при большом количестве атрибутов – это могут быть очень сильные тормоза; трудности при масштабировании; трудность в обеспечении целостности данных.

Плюсы: универсальность; гибкость и относительная простота при добавлении\удаление\редактирование характеристики товара.

Когда стоит применять? Всё исходя из плюсов: если характеристики для товаров очень динамичны и часто изменяются.

Заметки на полях. EAV используется, пожалуй, в одном из самых распространённых решений для создания интернет-магазина – Magento. Довольно занятная презентация Билла Карвина об антипаттернах в MySQL и EAV в том числе.

2. One table Это наиболее типичный и простой вариант архитектурного решения, для небольшого интернет-магазина со скромным количеством типов продаваемых товаров и практически не изменяемым набором атрибутов. Суть его заключается в следующем: для ВСЕХ типов товаров существует только одна таблица. Т.о. характеристики для жёстких дисков, оперативной памяти и пр. будут храниться в одной единственной таблице, а неиспользуемые поля, например, интерфейс, буфер, скорость вращения шпинделя – для оперативной памяти будут “забиваться” NULL значениями.

Минусы: сложность администрирования; избыточность данных; неудобство добавления\редактирования товаров.

Плюсы для этого решения описать сложно. Их скорее нет. Больше всего подойдёт в тех случаях, если набор характеристик товаров отличается не значительно.

3. Flat tables Этот способ заключается в том, что для каждого типа товара (фотоаппараты, мобильные телефоны, косметика и пр.) будет создаваться своя таблица. И если понадобится добавить, изменить или удалить поле, то это будет осуществляться при помощи SQL-запросов, например: ALTER TABLE `my_table` ADD `my_field` TINYINT( 1 ) NOT NULL DEFAULT ‘0’; или ALTER TABLE `my_table` DROP `my_field`;

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

Особенно “страшна” для нас блокировка таблиц, т.к. это, по сути, приведёт к остановке работоспособности магазина и, следовательно, к потере денег. Хотя, конечно, есть различные варианты решения данной проблемы. Например, создание временной копии таблицы, с которой и проделаем нужные операции по изменению структуры – это хоть и будет нагружать сервер, но не заблокирует основную таблицу на чтение, с которой работают пользователи магазина. Отмечу, что необходимо устанавливать блокировку на запись для таблицы с товарами, чтобы предотвратить добавление, а, следовательно, и потерю новых данных до того, как мы создадим полную копию таблицы и сделаем из неё основную.

Как дополнение, можно общий набор атрибутов хранить в отдельной таблице, но к магазину, торгующему очень разношерстными товарами – это не поможет. Дело в том, что для одной группы товаров будет один общий набор характеристик, для другой группы – другой набор, причём эти наборы могут пересекаться. Таким образом мы только усложним всё.

Минусы: полная блокировка таблиц; потенциально долгий процесс по изменению структуры таблицы; требует бОльших вычислительных ресурсов на сервере.

4. Документо-ориентированная база данных Этот вариант решения проблемы с возможность добавления\удаления сущностей не на основе реляционной СУБД типа MySQL, MSSQL и подобных, а на основе документо-ориентированных СУБД, типа CouchDB или MongoDB.

Подробный рассказ о документо-ориентированной базе и её различиях с классической реляционной моделью – тема отдельной статьи. Кто захочет сможет найти эту информацию в интернете. Для общего понимания темы, рекомендую прочесть вики. Вариант с ДО базой данных решает множество проблем и ограничений, который нас нас накладывает реляционная модель.

Пример того, как это всё будет выглядеть можно увидеть в документации на офф. сайте монго.

В чем же её основная привлекательность? В быстром и относительно безболезненном добавлении новых сущностей и атрибутов плюс высокая скорость получения данных.

Минусы: это нереляционно; требует значительных затрат времени программистов и администраторов на реализацию программной части для работы интернет-магазина; требует собственный сервер (как минимум VDS), т.к. практически не один shared хостинг не предоставляет эти СУБД.

Плюсы высокая скорость работы.

Вывод

Существует ещё множество различных ньюансов. Например, “Производитель”, является ли он свойством или нужно вынести его в отдельную таблицу. И как поступить правильно – решать исходя из задачи и множества других факторов.

Каков общий вывод я сделал? Всё очень индивидуально. В борьбе за полной универсальностью мы будем терять скорость и увеличивать сложность понимания и создания архитектуры. Всегда нужно исходить из задачи и искать компромиссное решение, которое может быть найдено при детальном анализе. В каких-то случаях лучшим решением будет EAV, в каких-то Flat tables, а где-то можно применить гибридное решение.

Бонус

В качестве бонуса дам ссылку на структуру БД самого большого “конструктора” по построению интернет-магазина – Magento. Посмотреть можно здесь. Надеюсь, данная статья помогла вам в понимании темы или натолкнула на какие-либо продуктивные мысли. Удачного дня!