Дизайн базы данных: объекты с разными атрибутами - PullRequest
4 голосов
/ 26 апреля 2010

Я разрабатываю базу данных продуктов, в которой продукты могут иметь очень разные атрибуты в зависимости от их типа, но атрибуты фиксированы для каждого типа, а типы вообще не поддаются управлению. E.g.:

журнал: название, номер выпуска, страницы, копии, дата закрытия, дата выпуска
веб-сайт: имя, пропускная способность, хиты, дата_от, дата_в

Я хочу использовать InnoDB и обеспечивать целостность базы данных настолько, насколько позволяет движок. Какой рекомендуемый способ справиться с этим?

Я ненавижу те проекты, в которых таблицы имеют 100 столбцов, и большинство значений NULL, поэтому я подумал о чем-то вроде этого:

product_type
============

product_type_id INT
product_type_name VARCHAR

product
=======

product_id INT
product_name VARCHAR
product_type_id INT -> Foreign key to product_type.product_type_id
valid_since DATETIME
valid_to DATETIME

magazine
========

magazine_id INT
title VARCHAR
product_id INT -> Foreign key to product.product_id
issue_number INT
pages INT
copies INT
close_date DATETIME
release_date DATETIME

web_site
========

web_site_id INT
name VARCHAR
product_id INT -> Foreign key to product.product_id
bandwidth INT
hits INT
date_from DATETIME
date_to DATETIME

Это может справиться с каскадным удалением продуктов, но ... Ну, я не до конца убежден ...

Ответы [ 3 ]

5 голосов
/ 26 апреля 2010

Это классический ОО-дизайн для несоответствия импеданса реляционных таблиц. Описанный вами дизайн таблицы известен как «таблица на подкласс». Все три наиболее распространенных проекта - это компромиссы по сравнению с тем, как на самом деле выглядят ваши объекты в вашем приложении:

  1. Таблица по конкретному классу
  2. Таблица в иерархии
  3. Таблица на подкласс

Дизайн, который вам не нравится - «где таблицы имеют 100 столбцов, а большинство значений NULL» - это 2. одна таблица для хранения всей иерархии специализации. Это наименее гибкий подход по всем причинам, в том числе - если вашему приложению требуется новый подкласс, необходимо добавить столбцы. Конструкция, которую вы описываете, учитывает изменения намного лучше, потому что вы можете добавить расширение, добавив новую таблицу подклассов, описанную значением в product_type.

Оставшийся вариант - 1. Таблица для каждого конкретного класса - обычно нежелательна из-за дублирования, возникающего при реализации всех общих полей в каждой таблице специализации. Хотя преимущества в том, что вам не нужно выполнять никаких объединений, а таблицы подклассов могут даже находиться в разных экземплярах БД в очень большой системе.

Описанный вами дизайн вполне жизнеспособен. Вариант ниже - это может выглядеть, если вы используете инструмент ORM для выполнения операций CRUD. Обратите внимание, как идентификатор в каждой таблице подкласса является значением FK для родительской таблицы в иерархии. Хороший ORM будет автоматически управлять правильной таблицей CRUD подкласса на основе значения значений дискриминатора только в product.id и product.product_type_id. Планируете ли вы использовать ORM или нет, посмотрите документацию присоединенного подкласса hibernate, хотя бы для того, чтобы увидеть решения, которые они приняли.

product
=======

id INT
product_name VARCHAR
product_type_id INT -> Foreign key to product_type.product_type_id
valid_since DATETIME
valid_to DATETIME

magazine
========

id INT -> Foreign key to product.product_id
title VARCHAR
..

web_site
========

id INT -> Foreign key to product.product_id INT
name VARCHAR
..
2 голосов
/ 26 апреля 2010

Вы, похоже, находитесь на правильном пути, за исключением того, что вам, возможно, придется учитывать разницу между «продуктом» и тем, что часто называют «единицей хранения» (SKU). Является ли коробка для скрепок на 25 единиц (определенного типа) тем же «продуктом», что и коробка на 50 единиц? С точки зрения магазина или любого вида инвентарной системы, различие имеет значение; в некоторых случаях, действительно, простое различие в упаковке от того, что в остальном является одним и тем же количеством того же базового «продукта», может дать вам различные SKU для отслеживания.

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

1 голос
/ 26 апреля 2010

Это на самом деле стандартный способ «навязывания» своего рода ОО-дизайна в классической СУБД.

Все «общие» атрибуты попадают в основную таблицу (например, цена, если она поддерживается на уровне таблицы продуктов, может легко входить в основную таблицу), в то время как подробности переходят в подтаблицу.

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

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

С другой стороны, обычная операция, такая как удаление элемента (я бы предложил логическое удаление, установив флаг «true» в основной таблице), будет выполняться один раз для каждого вида подтипа.

Во всяком случае, пойти на это. И, может быть, поискать «Объект, ориентированный на сопоставления СУБД» или что-то вроде полное обсуждение .

...