Гость
Форумы / Разработка информационных систем [игнор отключен] [закрыт для гостей] / Как лучше организовать хранение истории сущности? / 7 сообщений из 7, страница 1 из 1
28.09.2011, 15:38
    #37459306
Dymytry
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как лучше организовать хранение истории сущности?
День добрый!

Посоветуйте, пожалуйста, как лучше организовать хранение истории всех изменений некоей сущности?

Я вижу такие варианты:

1) Для каждой Entity - таблица где хранятся все ее состояния [проще сделать, сложнее выводить т.к. придется либо кодом проходить по всем полям и искать что изменилось, что убого, либо делать дополнительный View и туда класть изменения средствами БД]

2) Для каждой Entity - таблица где хранится разница с предыдущим состоянием (т.е. хранение изменений) [проще для GUI, но полноценной истории нет, если одно из изменений потеряно то дело плохо]

3) Универсальная таблица где хранятся все изменения или состояния в каком-то универсальном виде (например строка с разделителями которая содержит JSON с измененными полями и их значениями) [нереляционно как-то]

Что подсказывает Ваш опыт?
...
Рейтинг: 0 / 0
28.09.2011, 15:49
    #37459344
АнатоЛой
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как лучше организовать хранение истории сущности?
DymytryДень добрый!

Посоветуйте, пожалуйста, как лучше организовать хранение истории всех изменений некоей сущности?

Я вижу такие варианты:

1) Для каждой Entity - таблица где хранятся все ее состояния [проще сделать, сложнее выводить т.к. придется либо кодом проходить по всем полям и искать что изменилось, что убого, либо делать дополнительный View и туда класть изменения средствами БД]

2) Для каждой Entity - таблица где хранится разница с предыдущим состоянием (т.е. хранение изменений) [проще для GUI, но полноценной истории нет, если одно из изменений потеряно то дело плохо]

3) Универсальная таблица где хранятся все изменения или состояния в каком-то универсальном виде (например строка с разделителями которая содержит JSON с измененными полями и их значениями) [нереляционно как-то]

Что подсказывает Ваш опыт?

Опыт подсказывает, что вы предложили варианты решения, которые должны выбираться в соответствии с требованиями. А требований вы озвучили аж одно: "организовать хранение". И ни словом не обмолвились, для чего собираетесь хранить (как использовать) и какие есть нюансы (требования) этого использования.

Поэтому для Вас по требованиям подходят все три варианта, можете думать про ограничения "время", "деньги", "качество". :).
Если, конечно же, вы не поделитесь дополнительными требованиями.
И подскажу - аргументы "убого" обсуждать тяжело, ибо у всех участников будут разные системы координат для оценки "убогости". :)
...
Рейтинг: 0 / 0
28.09.2011, 15:55
    #37459364
Dymytry
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как лучше организовать хранение истории сущности?
АнатоЛой,

требования размытые: организовать логирование и показ изменений некоторых сущностей. То есть хранить и выводить таблицу Автор - Что Изменил (...) - Дата ИЛИ Автор - Значения полей - Дата. Я не могу решить какой вариант лучше и как это лучше организовать, поэтому и спрашиваю людей которые возможно набили на этом шишки. Что же здесь непонятного? :)
...
Рейтинг: 0 / 0
28.09.2011, 16:16
    #37459427
pilot911
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как лучше организовать хранение истории сущности?
Dymytry,

создай таблицу-копию с полем version_id
...
Рейтинг: 0 / 0
28.09.2011, 16:41
    #37459519
АнатоЛой
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как лучше организовать хранение истории сущности?
DymytryАнатоЛой,

требования размытые: организовать логирование и показ изменений некоторых сущностей. То есть хранить и выводить таблицу Автор - Что Изменил (...) - Дата ИЛИ Автор - Значения полей - Дата. Я не могу решить какой вариант лучше и как это лучше организовать, поэтому и спрашиваю людей которые возможно набили на этом шишки. Что же здесь непонятного? :)

1. Вот теперь понятно больше. А то может Вы просто забыли нам про требования рассказать :).
2. Выберите сначала какой вариант вывода результата лучше. Или нужно оба? Какой будет использоваться чаще?
1) Автор - Что Изменил (...) - Дата
2) Автор - Значения полей - Дата.

Если не можете определиться сами - сделайте пару примеров в ворде и покажите постановщику ваших "размытых требований".

3. Оценить затраты на реализацию предложенных Вами вариантов мы не можем: ничего не знаем про проект, технологии и т.д. и т.п., поэтому этот критерий вам оценивать самим.

4. Теперь отстранённо просто про варианты:

4.1. Вариант "отдельная таблица на сущность с полным состоянием на момент времени" - перечень полей понятен - те же, что у сущности + пара новых "служебных".
1) желательно именно отдельная - не придётся переделывать существующий функционал.
2) "убогого" в решении ничего не вижу - прост в реализации - это не убог. Простой выбор, когда именно мы несём вычислительные затраты на получение отчёта по истории изменений: в этом варианте напрягаем комп сравнением изменений как раз в момент, когда нужен отчёт - но удваиваем ввод-вывод по БД при изменении .
3) если понадобится функционал "выдай мне состояние всех атрибутов сущности на момент X" - вуаля, всё хранится в готовом виде.

4.2. "отдельная таблица на сущность с разницей от предыдущего состояния" - непонятен перечень полей для такой таблицы. можно пример?
но минус уже виден - разницу нужно посчитать в момент изменения - и если она уже не считается в процессе для других целей, то это доп.нагрузка на основной процесс (и такая нагрузка для некоторых будет выглядеть "убого" :) ).

4.3. "А-ля JSON" имеет право на жизнь - всё зависит от уже используемых в проекте технологий.
Недостаток - при обработке запись полностью извлекается из БД, если:
пользователя интересует не только простыня изменений, а чтобы ответ на вопрос: "Кто последним поменял ОКПО у контрагента Ч?" выдавался парой строк по заданным пользователем параметрам к отчёту изменений, а не поиском пальцем слова "ОКПО" в 5 листах распечатки по одному контрагенту.

Ваш нереляционный вариант с JSON и историей изменений может быть и более "реляционным": History_of_Changes(id, entity_name, entity_id, field_name, old_value, new_value), где x_value - имеет достаточного запаса по типу данных для логирования изменений.
"-" - нужно оценивать возможный перерасход места в БД из-за "больших" размеров типов old_value и new_value.

Ещё опыт подсказывает, что если есть свой фреймворк и метаописание сущностей, то необходимость логирования той или иной сущности указывайте в метаописании - и по-любому логируйте изменения самих метаописаний.
...
Рейтинг: 0 / 0
28.09.2011, 16:58
    #37459564
PL99
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как лучше организовать хранение истории сущности?
DymytryАнатоЛой,

требования размытые: организовать логирование и показ изменений некоторых сущностей. То есть хранить и выводить таблицу Автор - Что Изменил (...) - Дата ИЛИ Автор - Значения полей - Дата. Я не могу решить какой вариант лучше и как это лучше организовать, поэтому и спрашиваю людей которые возможно набили на этом шишки. Что же здесь непонятного? :)
Имхо, проще всего как-то так (разумеется, есть ряд ограничений):
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
CREATE TABLE LOG_HEADER
(
  ID_LOG_HEADER    NUMBER( 18 ),
  TBL_NAME         VARCHAR2( 255  BYTE)           NOT NULL,
  ACTION           VARCHAR2( 15  BYTE)            NOT NULL,
  DT_CHANGE        DATE                         DEFAULT SYSDATE               NOT NULL,
  USER_CHANGE      VARCHAR2( 255  BYTE)           DEFAULT USER                  NOT NULL,
  HOST_CHANGE      VARCHAR2( 255  BYTE),
  TERMINAL_CHANGE  VARCHAR2( 255  BYTE),
  IP_CHANGE        VARCHAR2( 15  BYTE),
  OS_USER_CHANGE   VARCHAR2( 255  BYTE),
  MODULE_CHANGE    VARCHAR2( 255  BYTE),
  ID               NUMBER( 18 )
)
LOGGING 
NOCOMPRESS 
NOCACHE
NOPARALLEL
MONITORING;

COMMENT ON TABLE LOG_HEADER IS 'Логирование изменений данных';

COMMENT ON COLUMN LOG_HEADER.ID_LOG_HEADER IS 'Код записи';

COMMENT ON COLUMN LOG_HEADER.TBL_NAME IS 'Изменяемая таблица';

COMMENT ON COLUMN LOG_HEADER.ACTION IS 'Действие (insert, update, delete)';

COMMENT ON COLUMN LOG_HEADER.DT_CHANGE IS 'Дата изменения';

COMMENT ON COLUMN LOG_HEADER.USER_CHANGE IS 'Кто изменил';

COMMENT ON COLUMN LOG_HEADER.HOST_CHANGE IS 'Машина';

COMMENT ON COLUMN LOG_HEADER.TERMINAL_CHANGE IS 'Терминал';

COMMENT ON COLUMN LOG_HEADER.IP_CHANGE IS 'IP адрес';

COMMENT ON COLUMN LOG_HEADER.OS_USER_CHANGE IS 'Пользователь';

COMMENT ON COLUMN LOG_HEADER.MODULE_CHANGE IS 'Программа';

COMMENT ON COLUMN LOG_HEADER.ID IS 'Код измененной записи';

ALTER TABLE LOG_HEADER ADD (
  CONSTRAINT LOG_HEADER_PK
  PRIMARY KEY
  (ID_LOG_HEADER)
  USING INDEX LOG_HEADER_PK);

CREATE TABLE LOG_ITEM
(
  ID_LOG_ITEM    NUMBER( 18 ),
  ID_LOG_HEADER  NUMBER( 18 )                     NOT NULL,
  COL_NAME       VARCHAR2( 255  BYTE)             NOT NULL,
  OLD_VALUE      VARCHAR2( 2000  CHAR),
  NEW_VALUE      VARCHAR2( 2000  CHAR),
  COL_COMMENT    VARCHAR2( 255  CHAR)
)
LOGGING 
NOCOMPRESS 
NOCACHE
NOPARALLEL
MONITORING;

COMMENT ON COLUMN LOG_ITEM.ID_LOG_ITEM IS 'Код строки изменения';

COMMENT ON COLUMN LOG_ITEM.ID_LOG_HEADER IS 'Заголовок';

COMMENT ON COLUMN LOG_ITEM.COL_NAME IS 'Поле';

COMMENT ON COLUMN LOG_ITEM.OLD_VALUE IS 'Старое значение';

COMMENT ON COLUMN LOG_ITEM.NEW_VALUE IS 'Новое значение';

COMMENT ON COLUMN LOG_ITEM.COL_COMMENT IS 'Наименование поля';

ALTER TABLE LOG_ITEM ADD (
  FOREIGN KEY (ID_LOG_HEADER) 
  REFERENCES LOG_HEADER (ID_LOG_HEADER));


CREATE OR REPLACE  PROCEDURE LOG_INSERT
    (
     aID_LOG_HEADER   IN LOG_HEADER.ID_LOG_HEADER%TYPE
    ,aTBL_NAME        IN LOG_HEADER.TBL_NAME%TYPE
    ,aACTION          IN LOG_HEADER.ACTION%TYPE
    ,aID              IN LOG_HEADER.ID%TYPE
    ) IS
lDT_CHANGE       LOG_HEADER.DT_CHANGE%TYPE;
lUSER_CHANGE     LOG_HEADER.USER_CHANGE%TYPE;
lHOST_CHANGE     LOG_HEADER.HOST_CHANGE%TYPE;
lTERMINAL_CHANGE LOG_HEADER.TERMINAL_CHANGE%TYPE;
lIP_CHANGE       LOG_HEADER.IP_CHANGE%TYPE;
lOS_USER_CHANGE  LOG_HEADER.OS_USER_CHANGE%TYPE;
lMODULE_CHANGE   LOG_HEADER.MODULE_CHANGE%TYPE;
  BEGIN
  SELECT sysdate
  ,sys_context('USERENV', 'SESSION_USER')
  ,sys_context('USERENV', 'HOST') 
  ,sys_context('USERENV', 'TERMINAL')
  ,sys_context('USERENV', 'IP_ADDRESS')
  ,sys_context('USERENV', 'OS_USER')
  ,sys_context('USERENV', 'MODULE') 
  into
lDT_CHANGE        
,lUSER_CHANGE      
,lHOST_CHANGE      
,lTERMINAL_CHANGE  
,lIP_CHANGE        
,lOS_USER_CHANGE   
,lMODULE_CHANGE    
  FROM dual;
    INSERT INTO LOG_HEADER
      (
       ID_LOG_HEADER
      ,TBL_NAME
      ,ACTION
      ,DT_CHANGE
      ,USER_CHANGE
      ,HOST_CHANGE
      ,TERMINAL_CHANGE
      ,IP_CHANGE
      ,OS_USER_CHANGE
      ,MODULE_CHANGE
      ,ID
      )
    VALUES
      (
       aID_LOG_HEADER
      ,aTBL_NAME
      ,aACTION
      ,lDT_CHANGE
      ,lUSER_CHANGE
      ,lHOST_CHANGE
      ,lTERMINAL_CHANGE
      ,lIP_CHANGE
      ,lOS_USER_CHANGE
      ,lMODULE_CHANGE
      ,aID
      );
  END LOG_INSERT;


CREATE OR REPLACE TRIGGER BIUD_TBL_ITEM_LOG
BEFORE INSERT OR UPDATE
ON TBL
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE

	lID_Header  NUMBER;
lAction varchar2( 20 );
begin
if INSERTING THEN lAction:='INSERT' ;
elsif UPDATING then lAction:='UPDATE';
end if;
select SQ.nextval into lID_Header from dual;
 
LOG_INSERT
    (
     aID_LOG_HEADER   => lID_Header
    ,aTBL_NAME        => 'TBL'
    ,aACTION          =>  lAction  
    ,aID              => :new.ID_TBL
    );


    INSERT INTO LOG_ITEM (ID_LOG_ITEM, ID_LOG_HEADER, COL_NAME, OLD_VALUE, NEW_VALUE, COL_COMMENT)VALUES (SQ.nextval, lID_Header,'ID_TBL' , to_char (lr_doc_old.ID_ADDITION), to_char (lr_doc.ID_ADDITION), 'Код');
    INSERT INTO LOG_ITEM (ID_LOG_ITEM, ID_LOG_HEADER, COL_NAME, OLD_VALUE, NEW_VALUE, COL_COMMENT)VALUES (SQ.nextval, lID_Header,'NUM' , lr_doc_old.NUM, lr_doc.NUM, 'Номер');
    INSERT INTO LOG_ITEM (ID_LOG_ITEM, ID_LOG_HEADER, COL_NAME, OLD_VALUE, NEW_VALUE, COL_COMMENT)VALUES (SQ.nextval, lID_Header,'DT' , to_char (lr_doc_old.DT), to_char (lr_doc.DT), 'Дата');
    INSERT INTO LOG_ITEM (ID_LOG_ITEM, ID_LOG_HEADER, COL_NAME, OLD_VALUE, NEW_VALUE, COL_COMMENT)VALUES (SQ.nextval, lID_Header,'DTYPE' , to_char (lr_doc_old.DTYPE), to_char (lr_doc.DTYPE), 'Тип документа: 1-дополнение, 2-спецификация');
    INSERT INTO LOG_ITEM (ID_LOG_ITEM, ID_LOG_HEADER, COL_NAME, OLD_VALUE, NEW_VALUE, COL_COMMENT)VALUES (SQ.nextval, lID_Header,'STATUS' , to_char (lr_doc_old.STATUS), to_char (lr_doc.STATUS), 'Статус');

    delete from log_item where ID_LOG_HEADER = lID_Header and (OLD_VALUE = NEW_VALUE or (NEW_VALUE is null and OLD_VALUE is null));
END BIUD_TBL_ITEM_LOG;

Триггер генерится скриптом, которому передается имя таблицы.

Допиливать по вкусу.
...
Рейтинг: 0 / 0
30.09.2011, 16:08
    #37463142
Кифирчик
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как лучше организовать хранение истории сущности?
Dymytry...2) Для каждой Entity - таблица где хранится разница с предыдущим состоянием (т.е. хранение изменений) [проще для GUI, но полноценной истории нет, если одно из изменений потеряно то дело плохо]...
сталкивался с таким "журналированием изменений"...
упрощенно
- сущность
- поле
- старое значение
- новое
- время изменения

по сути прикручивается чтоб собирались данные по любым таблицам БД... не такой-то и большой объем...

на практике, поднакопились данные за несколько лет... и когда надо было восстановить ситуацию, нужно было смотреть в виде "таблицы истории" для определеных записей сущности... это все выполнялось неприлично длительное время... не могу сказать чтоб были кривые запросы и медленные сервера...
зачастую забивали на этот "секс" и старались обходиться без лазания по такому "журналу"
...
Рейтинг: 0 / 0
Форумы / Разработка информационных систем [игнор отключен] [закрыт для гостей] / Как лучше организовать хранение истории сущности? / 7 сообщений из 7, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]