У вас есть как минимум пять вариантов моделирования описываемой иерархии типов:
Единая таблица наследования : одна таблица для всех типов продуктов с достаточным количеством столбцов для хранения всех атрибутов всех типов. Это означает множество столбцов, большинство из которых имеют NULL в любой данной строке.
Наследование таблицы классов : одна таблица для продуктов, в которой хранятся атрибуты, общие для всех типов продуктов. Затем по одной таблице для каждого типа продукта, в которой хранятся атрибуты, относящиеся к этому типу продукта.
Наследование конкретной таблицы : нет таблицы для общих атрибутов продуктов. Вместо этого одна таблица для каждого типа продукта, в которой хранятся как общие атрибуты продукта, так и атрибуты, специфичные для продукта.
Сериализованный LOB : одна таблица для продуктов, в которой хранятся атрибуты, общие для всех типов продуктов. В одном дополнительном столбце хранится большой двоичный объект частично структурированных данных в XML, YAML, JSON или другом формате. Этот большой двоичный объект позволяет хранить атрибуты, специфичные для каждого типа продукта. Вы можете использовать причудливые шаблоны дизайна, чтобы описать это, например фасад и сувенир. Но независимо от того, есть ли у вас множество атрибутов, которые нелегко запросить в SQL; вам нужно вернуть весь BLOB-объект в приложение и отсортировать его там.
Entity-Attribute-Value : одна таблица для продуктов и одна таблица, которая объединяет атрибуты в строки, а не столбцы. EAV не является правильным дизайном с точки зрения реляционной парадигмы, но многие люди все равно его используют. Это «Шаблон свойств», упомянутый в другом ответе. Посмотрите другие вопросы с тегом eav на StackOverflow, чтобы узнать о некоторых подводных камнях.
Подробнее об этом я написал в презентации Extensible Data Modeling .
Дополнительные мысли о EAV: Хотя многие люди, кажется, предпочитают EAV, я нет. Это кажется наиболее гибким решением, а значит, и лучшим. Однако имейте в виду пословицу ТАНСТААФЛ . Вот некоторые из недостатков EAV:
- Невозможно сделать столбец обязательным (эквивалент
NOT NULL
).
- Невозможно использовать типы данных SQL для проверки записей.
- Невозможно обеспечить единообразное написание имен атрибутов.
- Невозможно поместить внешний ключ в значения любого заданного атрибута, например, для таблицы поиска.
- Получение результатов в обычном табличном макете сложно и дорого, потому что для получения атрибутов из нескольких строк вам нужно делать это
JOIN
для каждого атрибута.
Степень гибкости, которую дает вам EAV, требует жертв в других областях, вероятно, делая ваш код таким же сложным (или хуже), чем это было бы при решении исходной проблемы более традиционным способом.
И в большинстве случаев такая гибкость не требуется. В вопросе OP о типах продуктов намного проще создать таблицу для каждого типа продукта для конкретных атрибутов продукта, поэтому у вас есть некоторая согласованная структура, применяемая, по крайней мере, для записей одного и того же типа продукта.
Я бы использовал EAV только в том случае, если каждой строке должно быть разрешено потенциально иметь отдельный набор атрибутов. Когда у вас есть конечный набор типов продуктов, EAV будет излишним. Первым моим выбором было бы наследование таблицы классов.
Обновление 2019: чем больше я вижу людей, использующих JSON в качестве решения проблемы «множества настраиваемых атрибутов», тем меньше мне нравится это решение. Это делает запросы слишком сложными, даже если для их поддержки используются специальные функции JSON . Для хранения документов JSON требуется гораздо больше места для хранения, чем для хранения в обычных строках и столбцах.
По сути, ни одно из этих решений не является простым или эффективным в реляционной базе данных. Сама идея наличия «переменных атрибутов» принципиально расходится с теорией отношений.
Все сводится к тому, что вам нужно выбрать одно из решений, в зависимости от которого оно наименее вредно для вашего приложения. Поэтому вам необходимо знать, как вы собираетесь запрашивать данные, прежде чем выбирать дизайн базы данных. Невозможно выбрать одно «лучшее» решение, потому что любое из решений может быть лучшим для данного приложения.
@Каменное сердце
Я бы пошел сюда с EAV и MVC полностью.
@ Билл Карвин
Все, что вы здесь упомянули:
на мой взгляд, они вообще не принадлежат базе данных, потому что ни одна из баз данных не способна обрабатывать эти взаимодействия и требования на должном уровне, как это делает язык программирования приложения.
На мой взгляд, использование базы данных подобным образом похоже на использование камня для забивания гвоздя. Вы можете сделать это с помощью камня, но разве вы не собираетесь использовать более точный молоток, специально разработанный для этого вида деятельности?
Эту проблему можно решить, сделав несколько запросов к частичным данным и преобразовав их в табличную структуру с помощью вашего приложения. Даже если у вас есть 600 ГБ данных о товарах, вы можете обрабатывать их партиями, если вам нужны данные из каждой отдельной строки в этой таблице.
Идем дальше Если вы хотите улучшить производительность запросов, вы можете выбрать определенные операции, например, для составления отчетов или глобального текстового поиска, и подготовить для них индексные таблицы, в которых будут храниться необходимые данные и которые будут периодически обновляться, скажем, каждые 30 минут.
Вам даже не нужно беспокоиться о стоимости дополнительного хранилища данных, потому что оно становится все дешевле и дешевле с каждым днем.
Если вас по-прежнему беспокоит производительность операций, выполняемых приложением, вы всегда можете использовать Erlang, C ++, Go Language для предварительной обработки данных, а затем просто обрабатывать оптимизированные данные в своем основном приложении.
источник
you can always use Erlang, C++, Go Language to pre-process the data
Что ты имел в виду? Вместо БД использовать Go lang? Не могли бы вы подробнее рассказать об этом?Если я использую
Class Table Inheritance
значение:Что мне больше всего нравится из предложений Билла Карвина ... Я могу предвидеть один недостаток, который я попытаюсь объяснить, как не допустить превращения в проблему.
Какой план действий на случай непредвиденных обстоятельств я должен иметь, когда атрибут, который является общим только для 1 типа, затем становится общим для 2, затем 3 и т. Д.?
Например: (это всего лишь пример, а не моя настоящая проблема)
Если мы продаем мебель, мы можем продавать стулья, лампы, диваны, телевизоры и т. Д. Тип телевизора может быть единственным типом, который мы продаем, с потребляемой мощностью. Поэтому я бы поставил
power_consumption
атрибут наtv_type_table
. Но потом мы начали заниматься домашними кинотеатрами, у которых тоже естьpower_consumption
собственность. Хорошо, это всего лишь еще один продукт, поэтому я добавлю это поле к нему,stereo_type_table
так как это, вероятно, проще всего на данном этапе. Но со временем, по мере того как мы начинаем поставлять все больше и больше электроники, мы понимаем, чтоpower_consumption
это достаточно широко, чтобы быть вmain_product_table
. Что мне теперь делать?Добавьте поле в
main_product_table
. Напишите сценарий, чтобы перебрать электронику и поместить правильное значение из каждогоtype_table
вmain_product_table
. Затем отбросьте этот столбец из каждогоtype_table
.Теперь, если бы я всегда использовал один и тот же
GetProductData
класс для взаимодействия с базой данных, чтобы получить информацию о продукте; тогда, если какие-либо изменения в коде теперь требуют рефакторинга, они должны относиться только к этому классу.источник
У вас может быть таблица Product и отдельная таблица ProductAdditionInfo с 3 столбцами: идентификатор продукта, название дополнительной информации, значение дополнительной информации. Если цвет используется многими, но не всеми видами товаров, вы можете сделать его столбцом, допускающим значение NULL, в таблице товаров или просто поместить его в ProductAdditionalInfo.
Этот подход не является традиционным для реляционной базы данных, но я видел, как он часто используется на практике. Он может быть гибким и иметь хорошую производительность.
Стив Йегге назвал это шаблоном свойств и написал длинный пост об его использовании.
источник
3 columns: product ID, additional info name, additional info value
я понял концепцию. И я действительно делал это раньше и сталкивался с проблемами. Однако на данный момент я не помню, что это были за проблемы.