Кращі практики для історії / тимчасових таблиць?


11

Припустимо, у мене є об'єкт із певними полями, за якими я хочу відслідковувати історію, та певними полями, за якими я не хочу відслідковувати історію. З точки зору нормалізації, в порядку наступна схема:

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,
)

Я згоден з @Joel
HaBo

Відповіді:


7

З практичних причин доступу до даних слід використовувати структуру з першого варіанту, а натомість зберігати всі версії відстежуваних значень стовпців, включаючи поточну версію, у вашій таблиці історії.

Причиною цього є те, що загалом, коли ви хочете переглянути історію, ви хочете включити теперішню та всі минулі версії. Коли ви не хочете дивитися на історію, ви хочете, щоб вона не вийшла з межі. У багатьох випадках це означає йти так далеко, щоб відокремити історію в окрему схему або базу даних взагалі. Навіть якщо ви зберігаєте свою історію в тій же схемі, що і ваші поточні дані, будь-які запити, які враховують історичні дані (включаючи поточні значення), будуть набагато складнішими, оскільки вони мають по суті об'єднати два джерела.


2

Я вважаю за краще першу версію, тому що вам, ймовірно, дуже рідко потрібно бачити історію, але вам часто доведеться бачити поточне значення. Таблицю історії слід заповнити з тригера, тому вам не потрібно турбуватися про те, що дані синхронізуються взагалі. Отже, припустимо, у вас є мільйон записів у MyObject, і тоді у вас є 10 000 000 записів у MyObjectHistory. Ви дійсно хочете приєднатись до таблиці з такою кількістю записів, щоб отримати поточне значення?

Тепер, якщо вам потрібно буде запитувати історію так часто, як більш частою, ніж поточне значення, то друга стриктура спрацює. (І якщо ви збираєтеся відображати значення станом на певну дату, у мене буде поле початкового та кінцевого завершення, щоб зробити запит простішим.)

BTW Я б додав поле дати в таблицю історії, щоб я міг сказати, в якому порядку відбулися зміни. Ви не можете покладатися на особистість для тимчасового порядку. Плюс, якщо є питання про значення previosu і коли воно змінилося, вам потрібно буде knwo. Я також можу ввести значення для програми, від якої зміни відбулися (якщо у вас є кілька додатків) та / або особи, яка внесла зміни.


0

Існує пара важливих причин №1. Перший - питання розміру, який HLGEM вказує, але є й інші важливі.

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

Звичайно, можуть бути випадки, коли ви хочете повністю їх об'єднати (як це робимо для ставок податків у LedgerSMB), оскільки історичні дані можуть використовуватися для поточних розрахунків, а кількість записів, ймовірно, буде відносно невеликою.

Однак я припускаю, що зберігання об'єктів у подібних таблицях рідко призводить до гарних, нормалізованих конструкцій. На мій досвід, ви дійсно хочете деякої інкапсуляції між хорошим нормалізованим сховищем та об'єктною моделлю програми.


2
Що ви маєте на увазі під "капсуляцією між хорошим нормалізованим сховищем та об'єктною моделлю програми"? Ви б пояснили цю ідею чи подали приклад?
cubetwo1729
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.