Дебаты о дизайне:каковы хорошие способы хранения и управления версиями объектов?[закрыто]

StackOverflow https://stackoverflow.com/questions/11689

Вопрос

Сначала я намеренно оставляю это весьма расплывчатым.Я больше ищу дискуссий и вопросов, которые важнее, чем четких ответов.

Я занимаюсь разработкой приложения, которое выполняет что-то вроде управления портфелем.Дизайн, который у меня есть на данный момент,

  • Проблема:проблема, которую необходимо решить
  • Решение:предлагаемое решение одной или нескольких проблем
  • Отношение:связь между двумя проблемами, двумя решениями или проблемой и решением.Далее разбито на:
    • Родитель-потомок - своего рода категоризация/древовидная иерархия
    • Перекрытие – степень, в которой два решения или две проблемы действительно относятся к одной и той же концепции.
    • Адреса – степень, в которой проблема связана с решением.

Мой вопрос касается временной природы этих вещей.Проблемы то возникают, то исчезают.Решения имеют ожидаемую дату разрешения, но она может быть изменена по мере их разработки.Степень взаимоотношений может меняться со временем по мере развития проблем и решений.

Итак, вопрос:Каков наилучший дизайн для создания версий этих вещей, чтобы я мог получить как текущую, так и историческую перспективу моего портфолио?

Позже:возможно, мне следует задать более конкретный вопрос, хотя ответ @Eric Beard заслуживает внимания.

Я рассмотрел три проекта баз данных.Мне хватит каждого, чтобы показать свои недостатки.Мой вопрос:какой выбрать, или можно придумать что-нибудь получше?

1:Проблемы (и отдельно Решения) при управлении версиями являются самоссылающимися.

table problems
  int id | string name | text description | datetime created_at | int previous_version_id

  foreign key previous_version_id -> problems.id

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

2:Создайте новый тип отношений:Версия.

table problems
  int id | string name | text description | datetime created_at

Это просто переместит связь из таблиц «Проблемы» и «Решения» в таблицу «Отношения».Та же проблема дублирования, но, возможно, немного «чище», поскольку у меня уже есть абстрактная концепция отношений.

3:Используйте структуру, более похожую на Subversion;переместите все атрибуты проблемы и решения в отдельную таблицу и создайте их версию.

table problems
  int id

table attributes
  int id | int thing_id | string thing_type | string name | string value | datetime created_at | int previous_version_id

  foreign key (thing_id, thing_type) -> problems.id or solutions.id
  foreign key previous_version_id -> attributes.id

Это означает, что для загрузки текущей версии Проблемы или Решения мне нужно получить все версии атрибута, отсортировать их по дате и затем использовать самую последнюю.Возможно, это не так уж и страшно.Что мне кажется действительно плохим, так это то, что я не могу проверить тип этих атрибутов в базе данных.Что value столбец должен быть свободным текстом.я могу сделать name вынести ссылку в отдельный столбец attribute_names стол, в котором есть type столбец, но это не так сила правильный тип в attributes стол.

еще позже:ответ на комментарии @Eric Beard о многотабличных внешних ключах:

Увы, то, что я описал, упрощенно:есть только два типа Вещей (Проблемы и Решения).На самом деле у меня есть около 9 или 10 различных типов вещей, поэтому в соответствии с вашей стратегией у меня будет 9 или 10 столбцов внешних ключей.Я хотел использовать однотабличное наследование, но у вещей так мало общего, что было бы очень сильно расточительно делать объединение их в одну таблицу.

Это было полезно?

Решение

Хм, похоже на этот сайт...

Что касается дизайна базы данных, то вам может понадобиться система управления версиями, такая как SVN, где вы никогда не делаете никаких обновлений, а просто вставляете (с номером версии), когда что-то меняется.Это называется MVCC, управление многозначным параллелизмом.Wiki – еще один хороший пример этого.

Другие советы

@Гайус

foreign key (thing_id, thing_type) -> problems.id or solutions.id

Будьте осторожны с такими «многонаправленными» внешними ключами.Мой опыт показал, что производительность запросов резко снижается, когда условие соединения должно проверять тип, прежде чем определять, к какой таблице присоединиться.Это не кажется таким элегантным, но обнуляемым

problem_id and solution_id 

будет работать намного лучше.

Конечно, производительность запросов также пострадает от конструкции MVCC, когда вам придется добавить проверку для получения последней версии записи.Компромисс заключается в том, что вам никогда не придется беспокоиться о конфликтах с обновлениями.

Как вы думаете об этом:

проблемы со столом
int id | Строковое имя | Текст описание | DateTime create_at

таблица проблемы_ревизии
int revision | int id | Строковое имя | Текст описание | DateTime create_at
идентификатор внешнего ключа -> проблемы.id

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

  1. эффективный доступ к текущей версии - выбирайте проблемы как обычно
  2. схема, интуитивно понятная и близкая к реальности, которую вы хотите смоделировать
  3. соединения между таблицами в вашей схеме сохраняют эффективность
  4. используя номер версии для каждой бизнес-транзакции, вы можете управлять версиями записей таблицы, как это делает SVN для файлов.

Я полагаю, есть

Вариант 4:гибрид

Переместите общие атрибуты вещи в таблицу с одним наследованием, затем добавьте custom_attributes стол.Это упрощает использование внешних ключей, уменьшает дублирование и обеспечивает гибкость.Это не решает проблемы безопасности типов дополнительных атрибутов.Это также добавляет немного сложности, поскольку теперь у Вещи есть два способа иметь атрибут.

Если description и другие большие поля остаются в таблице Things, однако это также не решает проблему дублирования пространства.

table things
  int id | int type | string name | text description | datetime created_at | other common fields...
  foreign key type -> thing_types.id

table custom_attributes
  int id | int thing_id | string name | string value
  foreign key thing_id -> things.id

Рекомендуется выбрать такую ​​структуру данных, которая позволит легко ответить на общие вопросы, которые вы задаете о модели.Скорее всего, большую часть времени вас интересует текущая позиция.Иногда вам захочется углубиться в историю для поиска конкретных проблем и решений.

У меня были бы таблицы проблем, решений и взаимосвязей, отражающие текущую ситуацию.Также было бы problem_history, solution_history, и т. д. таблица.Это будут дочерние таблицы проблемы, но они также будут содержать дополнительные столбцы для VersionNumber и EffectiveDate.Ключом будет (ProblemId, VersionNumber).

Когда вы обновляете проблему, вы записываете старые значения в problem_history стол.Таким образом, возможны запросы на определенный момент времени, поскольку вы можете выбрать problem_history запись, действительная на конкретную дату.

Там, где я делал это раньше, я также создал представление UNION. problem и problem_history поскольку это иногда полезно в различных запросах.

Вариант 1 затрудняет запрос текущей ситуации, поскольку все ваши исторические данные смешаны с текущими данными.

Вариант 3 будет плохим для производительности запросов и неприятным для кодирования, поскольку вы будете получать доступ к множеству строк для того, что должно быть простым запросом.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top