2012-06-11 4 views
5

У нас есть требование в нашем приложении, где нам нужно хранить ссылки для последующего доступа.История базы данных

Пример: Пользователь может совершать счета за один раз и все ссылки (адрес клиента, расчетную сумму денег, описания продуктов), которые содержит этот счет-фактура, и расчеты должны храниться с течением времени.

Нам нужно как-то держать ссылки, но что, если, например, имя продукта меняется? Так почему-то нам нужно скопировать все, чтобы оно было задокументировано позже и не повлияло на изменения в будущем. Даже когда продукты удаляются, их необходимо просмотреть позже, когда счет хранится.

Какова наилучшая практика в отношении дизайна базы данных? Даже самый гибкий подход, например, когда пользователь хочет позже отредактировать свой счет и восстановить его из db?

Спасибо!

ответ

9

Вот один из способов сделать это:

enter image description here

По существу, мы никогда не изменять или удалять существующие данные. Мы «модифицируем» его, создавая новую версию. Мы «удалим» его, установив флаг DELETED.

Например:

  • Если продукт изменяет цену, мы вставляем новую строку в PRODUCT_VERSION то время как старые заказы сохраняются подключены к старой PRODUCT_VERSION и старой цене.
  • Когда покупатель меняет адрес, мы просто вставляем новую строку в CUSTOMER_VERSION и связываем с ней новые заказы, сохраняя старые заказы, связанные со старой версией.
  • Если продукт удален, мы его действительно не удаляем - мы просто устанавливаем флаг PRODUCT.DELETED, поэтому все заказы, исторически сделанные для этого продукта, остаются в базе данных.
  • Если клиент удален (например, потому что он просил незарегистрировать его), установите флаг CUSTOMER.DELETED.

Предостережения:

  • Если название продукта должно быть уникальным, что не может быть приведено в исполнение декларативно в модели выше. Вам нужно либо «продвинуть» NAME из PRODUCT_VERSION в PRODUCT, сделать его ключом и отказаться от возможности «развить» имя продукта, либо обеспечить уникальность только на последнем PRODUCT_VER (возможно, через триггеры).
  • Существует потенциальная проблема с конфиденциальностью клиента. Если клиент удален из системы, может быть желательно физически удалить свои данные из базы данных, и просто установка CUSTOMER.DELETED не сделает этого. Если это вызывает озабоченность, либо вычеркивайте конфиденциальные данные во всех версиях клиента, либо, наоборот, отключите существующие заказы от реального клиента и повторно подключите их к специальному «анонимному» клиенту, а затем физически удалите все версии клиентов.

В этой модели используется много идентифицирующих отношений. Это приводит к «жирным» внешним ключам и может быть проблемой хранения данных, поскольку MySQL не поддерживает передовое сжатие индекса (в отличие, скажем, от Oracle), но, с другой стороны, InnoDB always clusters the data на ПК, и эта кластеризация может быть полезной для производительности. Кроме того, ОБЪЕДИНЕНИЯ являются менее необходимыми.

Эквивалентная модель с неидентифицирующими отношениями и суррогатными ключами будет выглядеть следующим образом:

enter image description here

+0

Чтобы иметь уникальные имена продуктов, вы можете добавить таблицу с именами продуктов, где имя является pk, и ссылка на эту таблицу из PRODUCT_VERSION –

+0

@OweJessen У вас может быть таблица LATEST_PRODUCT_VERSION с уникальным именем, но это не так считать «декларативным» решением, так как вам придется вручную вставлять и удалять строки в этой таблице при создании новых версий продукта. Если вы не используете СУБД, которая может автоматически обновлять материализованные представления и обеспечивать их уникальность (например, индексированные представления MS SQL Server), поэтому сама СУБД поддерживает LATEST_PRODUCT_VERSION для вас. –

1

Вы можете добавить столбец в таблицу продуктов, указав, продается ли она. Затем, когда продукт «удален», вы просто устанавливаете флаг так, чтобы он больше не был доступен как новый продукт, но вы сохраняете данные для будущих поисков.

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

+0

Это второй пункт не поможет ему, если он хочет, чтобы исторически включать название продукта, как это было, когда это было продан. Скажем, тот же ItemId применяется к «Coke» до 1988 года, а затем к «Coke Classic» после этого, и он хочет знать, что он был назван «Coke» по более старым заказам. Ваше предложение - это то, чего он пытается избежать - любой отчет, который он генерирует с использованием нормализованных данных, покажет «Coke Classic» по всем заказам до 1988 года или нет. – David

+0

True .. одним из способов борьбы с этим было бы создать новый продукт для изменения имени или добавить другую таблицу для отслеживания имен продуктов (что подходит к решению @Branko Dimitrijevic). – whrrgarbl

1

Проблема, с которой вы столкнулись, является, как я уверен, вы знаете, результатом нормализации базы данных. Один из подходов к решению этого вопроса можно взять из методов бизнес-аналитики - архивирование данных в ненормированном состоянии в Data Warehouse.

Нормированная данные:

  • Заказы таблица
    • OrderId
    • CustomerId
  • Клиенты Таблица
    • CustomerId
    • Firstname
    • т.д.
  • Предметы Стол
    • ItemId
    • ITEMNAME
    • ItemPrice
  • OrderDetails Таблица
    • ItemDetailId
    • OrderId
    • ItemId
    • ItemQty
    • т.д.

При запросе и хранится де нормализованы, хранилище данных таблица выглядит

  • OrderId
  • CUSTOMERID
  • CUSTOMERNAME
  • CustomerAddress
  • (другого клиента Поля)
  • ItemDetailId
  • ItemId
  • ITEMNAME
  • ItemPrice
  • (Другие OrderDetail и пункт Fields)

Как правило, это либо какая-то запланированного задания, которое вытаскивает данные из нормализованных данных в хранилище данных по расписанию, ИЛИ, если ваш de знак позволяет, это можно сделать, когда заказ достигнет определенного статуса. (Например, отправлено). Возможно, записи сохраняются при каждом изменении статуса (с полем OrderStatus, который ссылается на текущий статус), поэтому полностью де-нормированные данные доступны для каждого этапа процесса опечатки/выполнения. Когда и как архивировать данные на склад будет отличаться в зависимости от ваших потребностей.


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

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

Так что если мой адрес AddressId 12, когда я первый заказ на вашем сайте в Jamnuary, то я переезжаю 4 июля, я получаю новый AddressId, привязанный к моей учетной записи. (Скажите AddressId 123123, потому что ваш сайт очень успешный и привлек тонну клиентов.)

Приказы, которые я скрепил до 4 июля, связали бы с ними AddressId 12, а заказы, размещенные на 4 июля или после него, имеют AddressId 123123.

Повторите этот шаблон с каждой таблицей, которая должна сохранять исторические данные.

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

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

+0

да .... что @ Давид Страттон сказал ... удалив мой более разговорный ответ той же идеи. – GDP

+0

@Greg P ​​- Я собирался проголосовать за вас. Ваш ответ более краткий и по-прежнему актуальный. – David

+0

Добавил его обратно для потомков ... не люблю повторять, когда есть более краткий ответ, спасибо. – GDP

1

Вы открыли вечную дискуссию между пуристским и практическим подходом.

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

Нормализованный подход «de» заключается в том, чтобы рассматривать этот счет как «момент времени», записывая в соответствующие таблицы данные, как это было в тот день. Такой подход позволяет вытащить этот счет без каких-либо зависимостей, но вы никогда не сможете восстановить этот счет с нуля.

0

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

Таким образом, таблица заказов может содержать имя и адрес клиента, в подробностях woudl содержится вся соответствующая информация о produtct, включая особенно цену (вы никогда не хотите полагаться на таблицу продуктов для информации о ценах за пределами первоначального поиска во время приказ).

Это НЕ денормализация, данные изменяются с течением времени, но вам нужно историческое значение, поэтому вы должны хранить его во время создания записи или потерять целостность данных. Вы не хотите, чтобы ваши финансовые отчеты внезапно указывали, что вы продали на 30% больше в прошлом году, потому что у вас есть обновления цен. Это не то, что вы продали.

+1

«Это НЕ денормализация ...» Правильно. В реляционных системах дублирующиеся данные означают «те же значения с тем же значением». Здесь значения могут быть одинаковыми, но значение отличается. (Текущая цена, например, по сравнению с ценой на момент заказа.) –

Смежные вопросы