Я работаю над обновлением базы данных продуктов нашего сайта. Он построен в MySQL, но это больше вопрос шаблона проектирования базы данных.
Я планирую перейти на шаблон Supertype / Subtype. Наша текущая / предыдущая база данных в основном представляет собой одну таблицу, в которой есть данные об одном типе продукта. Мы рассчитываем расширить ассортимент нашей продукции, чтобы включить в нее различные продукты.
Этот новый черновой вариант выглядит так:
Product product_[type] product_attribute_[name]
---------------- ---------------- ----------------------------
part_number (PK) part_number (FK) attributeId (PK)
UPC specific_attr1 (FK) attribute_name
price specific_attr2 (FK)
... ...
У меня вопрос по поводу таблиц атрибутов товара. Идея здесь заключается в том, что продукт может иметь список заданных атрибутов, таких как цвет: красный, зеленый, синий или материал: пластик, дерево, хром, алюминий и т. Д.
Этот список будет храниться в таблице, и первичный ключ (PK) для этого элемента атрибута будет использоваться в таблице конкретного продукта в качестве внешнего ключа (FK).
(Книга Мартина Фаулера « Шаблоны архитектуры корпоративных приложений» называется « Сопоставление внешнего ключа »)
Это позволяет интерфейсу веб-сайта извлекать список атрибутов для данного типа атрибута и выплевывать его в раскрывающемся меню выбора или в каком-либо другом элементе пользовательского интерфейса. Этот список можно считать «разрешенным» списком значений атрибутов.
Количество соединений, которое в конечном итоге происходит при извлечении определенного продукта, кажется мне чрезмерным. Вы должны присоединить каждую таблицу атрибутов продукта к продукту, чтобы получить поля этого атрибута. Обычно это поле может быть просто строкой (varchar) для его имени.
Этот шаблон проектирования в конечном итоге создает большое количество таблиц, а также вы получаете таблицу для каждого атрибута. Одной из идей противодействия этому было бы создание чего-то большего из таблицы «мешок для захвата» для всех атрибутов продукта. Что-то вроде этого:
product_attribute
----------------
attributeId (PK)
name
field_name
Таким образом, ваша таблица может выглядеть так:
1 red color
2 blue color
3 chrome material
4 plastic material
5 yellow color
6 x-large size
Это может помочь уменьшить проскальзывание таблицы, но это не уменьшает количество объединений, и он чувствует себя немного неправильно, объединяя так много разных типов в одну таблицу. Но вы сможете получить все доступные атрибуты «цвета» довольно легко.
Однако может существовать атрибут, который имеет больше полей, чем просто «имя», например значение RGB цвета. Это потребует, чтобы этот конкретный атрибут мог иметь другую таблицу или иметь одно поле для пары имя: значение (что имеет свои недостатки).
Последний шаблон проектирования, о котором я могу подумать, - это сохранение фактического значения атрибута в таблице конкретного продукта и отсутствие «таблицы атрибутов» вообще. Что-то вроде этого:
Product product_[type]
---------------- ----------------
part_number (PK) part_number (FK)
UPC specific_attr1
price specific_attr2
... ...
Вместо внешнего ключа к другой таблице он будет содержать фактическое значение, например:
part_number color material
----------- ----- --------
1234 red plastic
Это устранит соединения и предотвратит ползучесть таблиц (может быть?). Однако это предотвращает наличие «авторизованного списка» атрибутов. Вы можете вернуть все введенные в данный момент значения для данного поля (т. Е. Цвет), но это также устраняет идею наличия «разрешенного списка» значений для данного атрибута.
Чтобы получить этот список, вам все равно придется создать таблицу атрибутов «grab bag» или иметь несколько таблиц (таблица ползучести) для каждого атрибута.
Это создает больший недостаток (и почему я никогда не использовал этот подход), так как теперь название продукта находится в нескольких местах.
Если у вас есть значение цвета «красный» в «таблице основных атрибутов», а также вы сохранили его в таблице «product_ [type]», обновление таблицы «master» вызовет потенциальную проблему целостности данных, если приложение не Не обновляйте все записи со старым значением в таблице «product_type».
Итак, после моего многословного объяснения и анализа этого сценария я понял, что это не может быть необычным сценарием и даже может быть название для такого типа ситуации.
Существуют ли общепринятые решения этой проблемы дизайна? Приемлемо ли потенциально большое количество объединений, если таблицы относительно малы? Допустимо ли хранение имени атрибута вместо атрибута PK в некоторых ситуациях? Есть ли другое решение, о котором я не думаю?
Несколько заметок об этой базе данных / приложении:
- Продукты не часто обновляются / добавляются / удаляются
- Атрибуты не часто обновляются / добавляются / удаляются
- Таблица чаще всего запрашивается для чтения / возврата информации
- Кэширование на стороне сервера позволяет кэшировать результат данного запроса / результата
- Я планирую начать только с одного типа продукта и расширять / добавлять другие с течением времени, и потенциально будет иметь более 10 различных типов
источник
Ответы:
Я лично использовал бы модель, подобную следующей:
Таблица продуктов будет довольно простой, ваши основные данные продукта:
Вторая таблица атрибутов для хранения каждого из различных атрибутов.
Наконец, создайте таблицу product_attribute как таблицу JOIN между каждым продуктом и его атрибутами, связанными с ним.
В зависимости от того, как вы хотите использовать данные, вы просматриваете два объединения:
Смотрите SQL Fiddle с демонстрацией . Это возвращает данные в формате:
Но если вы хотите вернуть данные в
PIVOT
формате, где у вас есть одна строка со всеми атрибутами в виде столбцов, вы можете использоватьCASE
операторы с агрегатом:Смотрите SQL Fiddle с демонстрацией . Данные возвращаются в формате:
Как вы видите, данные могут быть в лучшем формате для вас, но если у вас есть неизвестное количество атрибутов, они легко станут несостоятельными из-за жестко кодируемых имен атрибутов, поэтому в MySQL вы можете использовать подготовленные операторы для создания динамических сводок , Ваш код будет выглядеть следующим образом (см. SQL Fiddle With Demo ):
Это приводит к тому же результату, что и вторая версия, без необходимости что-либо кодировать. Хотя есть много способов смоделировать это, я думаю, что этот дизайн базы данных является наиболее гибким.
источник
Я бы расширил ответ Тэрина и изменил бы таблицу атрибутов, чтобы иметь столбец fk_attribute_type_id, который будет вместо столбца attribute_name и указывает на новую таблицу attribute_type.
Таким образом, у вас есть структурированные типы атрибутов в одной таблице, и вы можете изменить их в любое время в одном месте.
На мой взгляд, лучше работать с вещами типа "dial" (таблица с возможными типами), чем с типом enum (например, в столбце attribute_name (и, кроме того, на самом деле это не name, а его тип атрибута)).
источник