Предположим, у меня есть объект, с определенными полями, которые я хочу отслеживать историю, и определенными полями, которые я не хочу отслеживать историю. С точки зрения нормализации, следующая схема в порядке:
CREATE TABLE MyObject AS (
MyObjectId INT IDENTITY NOT NULL PRIMARY KEY,
MyObjectField1 VARCHAR(100) NOT NULL,
MyObjectField2 VARCHAR(100) NOT NULL,
MyObjectField3 VARCHAR(100) NOT NULL,
MyObjectTrackedField1 VARCHAR(100) NOT NULL,
MyObjectTrackedField2 VARCHAR(100) NOT NULL,
MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)
CREATE TABLE MyObjectHistory AS (
MyObjectHistoryId INT IDENTITY NOT NULL PRIMARY KEY,
MyObjectId INT NOT NULL FOREIGN KEY REFERENCES MyObject(MyObjectId),
MyObjectTrackedField1 VARCHAR(100) NOT NULL,
MyObjectTrackedField2 VARCHAR(100) NOT NULL,
MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)
где MyObjectHistory содержит отслеживаемые поля для всех, кроме последней версии. Или, если все отслеживаемые поля должны быть в одной таблице, а все версии, включая самые последние, должны быть в этой таблице, как в:
CREATE TABLE MyObject AS (
MyObjectId INT IDENTITY NOT NULL PRIMARY KEY,
MyObjectField1 VARCHAR(100) NOT NULL,
MyObjectField2 VARCHAR(100) NOT NULL,
MyObjectField3 VARCHAR(100) NOT NULL,
)
CREATE TABLE MyObjectHistory AS (
MyObjectHistoryId INT IDENTITY NOT NULL PRIMARY KEY,
MyObjectId INT NOT NULL FOREIGN KEY REFERENCES MyObject(MyObjectId),
MyObjectTrackedField1 VARCHAR(100) NOT NULL,
MyObjectTrackedField2 VARCHAR(100) NOT NULL,
MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)
database-design
normalization
cubetwo1729
источник
источник
Ответы:
Из практических соображений доступа к данным вам следует использовать структуру из первого варианта, но вместо этого сохранить все версии значений отслеживаемого столбца, включая текущую версию, в таблице истории.
Причина этого заключается в том, что в целом, когда вы хотите посмотреть историю, вы хотите включить настоящую и все прошлые версии. Когда вы не хотите смотреть на историю, вы хотите убрать ее с дороги. Во многих случаях это означает, что история будет разделена на отдельную схему или базу данных. Даже если вы сохраните свою историю в той же схеме, что и ваши текущие данные, любые запросы, которые просматривают исторические данные (включая текущие значения), будут намного более сложными, поскольку они должны по существу объединять два источника.
источник
Я бы предпочел первую версию, потому что вам, вероятно, редко нужно видеть историю, но вам часто нужно видеть текущее значение. Таблица истории должна быть заполнена из триггера, поэтому вам не нужно беспокоиться о том, что данные вообще не синхронизируются. Предположим, у вас есть миллион записей в MyObject, а затем у вас есть 10 000 000 записей в MyObjectHistory. Вы действительно хотите присоединиться к таблице с таким количеством записей, чтобы получить текущее значение?
Теперь, если вам нужно будет запрашивать историю как часто или чаще, чем текущее значение, тогда будет работать вторая строка. (И если вы собираетесь отображать значение по состоянию на определенную дату, у меня было бы поле для поля имени и конца для упрощения запросов.)
Кстати, я бы добавил поле даты в таблицу истории, чтобы можно было определить порядок изменений. Вы не можете полагаться на идентичности для временного порядка. PLus, если есть вопрос о предыдущем значении и когда оно изменилось, вам нужно будет знать. Я мог бы также указать значения для приложения, из которого получено изменение (если у вас несколько приложений) и / или от лица, которое внесло изменение.
источник
Есть пара важных причин для № 1. Первая - это проблема размера, на которую указывает HLGEM, но есть и другие важные.
Как правило, в вашем контрольном журнале со временем будут развиваться требования. Возможно, вы захотите отследить пользователей базы данных, время изменений и т. Д. Требования к журналу аудита и ваша основная таблица, вероятно, со временем изменятся несколько независимо. Наконец, вы, вероятно, захотите очистить данные контрольного журнала по истечении определенного периода времени независимо и полностью разделить таблицу.
Конечно, могут быть случаи, когда вы хотите полностью объединить их (как мы делаем для налоговых ставок в LedgerSMB), потому что исторические данные могут использоваться для текущих расчетов, и число записей, вероятно, будет относительно небольшим.
Я собираюсь предположить, однако, что хранение объектов в таких таблицах редко приводит к хорошим, нормализованным проектам. По моему опыту, вы действительно хотите некоторую инкапсуляцию между хорошим нормализованным хранилищем и объектной моделью приложения.
источник