Проектирование базы данных SQL для представления иерархии классов OO

Я собираюсь преобразовать иерархию классов, которая будет храниться в базе данных SQL.

Оригинальный псевдокод:

abstract class Note
{
   int id;
   string message;
};

class TimeNote : public Note
{
   time_t time;
};

class TimeRangeNote : public Note
{
   time_t begin;
   time_t end;
};

class EventNote : public Note
{
   int event_id;
};

// More classes deriving from Note excluded.

В настоящее время у меня есть пара идей, как сохранить это в базе данных.

а. Храните все заметки в одной широкой таблице

Таблица будет содержать всю информацию, необходимую всем классам, полученным из Note.

CREATE TABLE t_note(
   id INTEGER PRIMARY KEY,
   message TEXT,
   time DATETIME,
   begin DATETIME,
   end DATETIME,
   event_id INTEGER
);

В будущих классах, происходящих из Note, необходимо добавить новые столбцы в эту таблицу.

В. Сопоставьте каждый класс с таблицей

CREATE TABLE t_note(
   id INTEGER PRIMARY KEY,
   message TEXT
);

CREATE TABLE t_timenote(
   note_id INTEGER PRIMARY KEY REFERENCES t_note(id),
   time DATETIME
);

CREATE TABLE t_timerangenote(
   note_id INTEGER PRIMARY KEY REFERENCES t_note(id),
   begin DATETIME,
   end DATETIME
);

CREATE TABLE t_eventnote(
   note_id INTEGER PRIMARY KEY REFERENCES t_note(id),
   event_id INTEGER
);

В будущих классах, полученных из Note, необходимо создать новую таблицу.

С. Используйте нормализацию базы данных и VARIANT/SQL_VARIANT

CREATE TABLE t_note(
   id INTEGER PRIMARY KEY,
   message TEXT
);

CREATE TABLE t_notedata(
   note_id INTEGER REFERENCES t_note(id),
   variable_id TEXT, -- or "variable_id INTEGER REFERENCES t_variable(id)".
                     -- where t_variable has information of each variable.
   value VARIANT
);

В будущих классах, происходящих из Note, необходимо добавить новый variable_id.

Д. Сопоставьте каждый конкретный класс с таблицей (недавно добавленный на основе текущих ответов)

CREATE TABLE t_timenote(
   id INTEGER PRIMARY KEY,
   message TEXT,
   time DATETIME
);

CREATE TABLE t_timerangenote(
   id INTEGER PRIMARY KEY,
   message TEXT,
   begin DATETIME,
   end DATETIME
);

CREATE TABLE t_eventnote(
   id INTEGER PRIMARY KEY,
   message TEXT,
   event_id INTEGER
);

В будущих классах, полученных из Note, необходимо создать новую таблицу.


Каким будет наиболее логичное представление в SQL?
Есть ли лучшие варианты?

Ответ 1

В общем, я предпочитаю obtion "B" (т.е. одна таблица для базового класса и одна таблица для каждого "конкретного" подкласса).

Конечно, это имеет несколько недостатков: в первую очередь вам нужно объединить хотя бы 2 таблицы, когда вам нужно прочитать полный экземпляр подкласса. Кроме того, "базовая" таблица будет постоянно доступна любому, кто должен работать на любом виде заметки.

Но это обычно приемлемо, если у вас нет крайних случаев (миллиарды строк, очень быстрое время отклика и т.д.).

Существует третий возможный вариант: сопоставьте каждый подкласс с отдельной таблицей. Это помогает разделить ваши объекты, но в целом больше затрат на разработку.

См. этот для полного обсуждения.

(Что касается вашего решения "C", используя VARIANT: я не могу комментировать достоинства/недостатки, потому что это похоже на проприетарное решение - что это такое? Transact-SQL? и я не знаком с ним).

Ответ 2

Ваш вариант "B", как описано, в значительной степени представляет собой реализацию "Подчиненности подкласса объекта" (Kung, 1990 http://portal.acm.org/citation.cfm?id=79213)

Таким образом, это хорошо установленный и понятный метод. Это работает очень хорошо. Он также расширяется через несколько уровней наследования, если вам это нужно.

Конечно, вы теряете некоторые преимущества инкапсуляции и скрытия информации, если вы не ограничиваете, кто может получить доступ к данным на интерфейсе СУБД.

Однако вы можете получить доступ к нему из нескольких систем и даже языков одновременно (например, Java, С++, С#) (Это было предметом моей магистерской диссертации:)

Ответ 3

Вы попали в 3 наиболее распространенных способа моделирования объектов в реляционную базу данных. Все 3 приемлемы, и каждый из них имеет свои плюсы и минусы. К сожалению, это означает, что нет правильного "правильного" ответа. Я реализовал каждый из них в разное время, и здесь пара примечаний/предостережений, о которых нужно помнить:

Вариант A имеет недостаток, что при добавлении нового подкласса вы должны изменить существующую таблицу (это может быть менее приемлемым для вас, чем добавление новой таблицы). Это также имеет недостаток, что многие столбцы будут содержать NULL. Тем не менее, современные БД кажутся МНОГО лучше в управлении пространством, чем старые БД, поэтому я никогда не был слишком обеспокоен ошибками. Одно из преимуществ заключается в том, что ни одна из ваших операций поиска или получения не потребует JOINs или UNION, что означает потенциально лучшую производительность и более простой SQL.

Вариант B имеет недостаток: если вы добавляете новое свойство в ваш суперкласс, вам нужно добавить новый столбец для каждой таблицы подкласса. Кроме того, если вы хотите выполнить гетерогенный поиск (все подклассы сразу), вы должны сделать это с помощью UNION или JOIN (возможно, более медленная производительность и/или более сложный sql).

Вариант C имеет недостаток, что все операции поиска (даже для одного подкласса) будут включать JOIN, как и большинство запросов. Кроме того, все вставки будут включать несколько таблиц, что сделает несколько более сложный SQL, и потребует использования транзакций. Этот вариант кажется самым "чистым" с точки зрения нормализации данных, но я редко использую его, потому что недостаток JOIN для каждой операции обычно делает один из других вариантов более приемлемым.

Ответ 4

Я бы отвлекся на вариант A.

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

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

В целом, но это может быть близко к религиозной дискуссии, поэтому будьте осторожны, я считаю, что реляционная база данных должна быть реляционной базой данных, а не пытаться имитировать структуру OO. Пусть ваши классы выполняют OO-материал, пусть db будет реляционным. Существуют специальные базы данных OO, если вы хотите расширить их до своего хранилища данных. Это означает, что вам нужно пересечь "несоответствие объектно-реляционного импеданса", как они его называют, но снова есть ORM-мапперы для этой конкретной цели.

Ответ 5

Я бы выбрал вариант A.

Решение B полезно, если иерархия классов очень сложна с десятками классов, наследующих друг друга. Это наиболее масштабируемое решение. Однако недостатком является то, что он делает SQL более сложным и медленным.

Для относительно простых случаев, таких как 4 или 5 классов, наследующих один и тот же базовый класс, имеет смысл выбрать решение A. SQL будет проще и быстрее. И накладные расходы на наличие дополнительных столбцов с NULL-значениями незначительны.

Ответ 6

Там есть серия моделей, коллективно известных как "Crossing Chasms", которые я использовал в течение многих лет. Не позволяйте ссылки на Smalltalk бросать вас - это применимо к любому объектно-ориентированному языку. Попробуйте следующие ссылки:

Язык шаблонов для реляционных баз данных и Smalltalk
Пересечение Chasms - Статические шаблоны
Пересечение Chasms - Архитектурные шаблоны

Поделитесь и наслаждайтесь.

ИЗМЕНИТЬ

Wayback Machine ссылается на все, что я смог найти в шаблонах Crossing Chasms: http://web.archive.org/web/20040604122702/http://www.ksccary.com/article1.htm http://web.archive.org/web/20040604123327/http://www.ksccary.com/article2.htm http://web.archive.org/web/20040604010736/http://www.ksccary.com/article5.htm http://web.archive.org/web/20030402004741/http://members.aol.com/kgb1001001/Chasms.htm http://web.archive.org/web/20060922233842/http://people.engr.ncsu.edu/efg/591O/s98/lectures/persistent-patterns/chasms.pdf http://web.archive.org/web/20081119235258/http://www.smalltalktraining.com/articles/crossingchasms.htm http://web.archive.org/web/20081120000232/http://www.smalltalktraining.com/articles/staticpatterns.htm

Я создал документ Word, который объединяет все вышеперечисленное в нечто похожее на целостное целое, но у меня нет сервера, на который я могу его добавить, чтобы сделать его общедоступным. Если кто-то может предложить бесплатный репозиторий документов, я был бы счастлив разместить там документ.