sai*_*int 17 database database-design
例如,我有一个表存储有关属性的详细信息.哪个可能有所有者,价值等
是否有一个好的设计,以保持每个变化的历史所有者和价值.我想为很多桌子做这个.有点像审计表.
我的想法是保留一个带有字段的单个表
table_name,field_name,prev_value,current_val,time,user.
但它看起来有点hacky和丑陋.有更好的设计吗?
谢谢.
Unr*_*son 24
有几种方法
基于现场
audit_field (table_name, id, field_name, field_value, datetime)
Run Code Online (Sandbox Code Playgroud)
这个可以捕获所有表的历史记录,并且很容易扩展到新表.新表不需要对结构进行任何更改.
Field_value有时会被拆分为多个字段,以便原始支持原始表中的实际字段类型(但只会填充其中一个字段,因此数据会非规范化;一种变体是将上表拆分为每种类型的一个表) .
其他元数据,如field_type,user_id,user_ip,action(更新,删除,插入)等可能很有用.
这些记录的结构很可能需要转换才能使用.
记录基础
audit_table_name (timestamp, id, field_1, field_2, ..., field_n)
Run Code Online (Sandbox Code Playgroud)
对于数据库中的每个记录类型,创建一个通用表,其中包含所有字段作为原始记录,以及版本控制字段(可能再次使用其他元数据).每个工作表都需要一张表.创建此类表的过程可以自动化.
这种方法为您提供了与主数据结构非常相似的语义丰富的结构,因此用于分析和处理原始数据的工具也可以很容易地用于此结构.
日志文件
前两种方法通常使用非常轻微索引的表(或根本没有索引且没有参照完整性),从而使写入惩罚最小化.尽管如此,有时平板日志文件可能是首选,但当然功能上大大减少了.(基本上取决于您是否需要由其他系统分析的实际审核/日志,或者历史记录是主系统的一部分).
另一种看待这种情况的方法是对数据进行时间维度.
假设你的表看起来像这样:
create table my_table (
my_table_id number not null primary key,
attr1 varchar2(10) not null,
attr2 number null,
constraint my_table_ak unique (attr1, att2) );
Run Code Online (Sandbox Code Playgroud)
然后,如果你改变它:
create table my_table (
my_table_id number not null,
attr1 varchar2(10) not null,
attr2 number null,
effective_date date not null,
is_deleted number(1,0) not null default 0,
constraint my_table_ak unique (attr1, att2, effective_date)
constraint my_table_pk primary key (my_table_id, effective_date) );
Run Code Online (Sandbox Code Playgroud)
您将能够拥有my_table,在线和可用的完整运行历史记录.您必须更改程序的范例(或使用数据库触发器)来拦截UPDATE活动到INSERT活动,并将DELETE活动更改为UPDATing IS_DELETED布尔值.
非理性:
你说这个解决方案类似于基于记录的审计是正确的; 我最初读它是一个字段连接成一个字符串,我也看到了.我很抱歉.
在时间维度表和使用基于记录的审计中心之间看到的主要区别在于可维护性而不牺牲性能或可伸缩性.
可维护性: 如果对主表进行结构更改,则需要记住更改影子表.同样,需要记住对执行更改跟踪的触发器进行更改,因为这样的逻辑不能存在于应用程序中.如果使用视图来简化对表的访问,您还必须更新它,并更改反对它的反向触发器来拦截DML.
在时间尺寸表中,您可以进行所需的结构更改,然后就完成了.作为一个遗留项目的FNG的人,这种清晰度是值得赞赏的,特别是如果你必须进行大量的重构.
性能和可伸缩性: 如果在有效/到期日期列上对时间维度表进行分区,则活动记录位于一个"表"中,而非活动记录位于另一个"表"中.究竟如何比您的解决方案更具可扩展性?"删除"和活动记录涉及Oracle中的行移动,这是一个删除和插入 - 正是基于记录的解决方案所需要的.
性能的另一面是,如果应用程序在某个日期查询记录,则分区消除允许数据库仅搜索记录所在的表/索引; 搜索活动和非活动记录的基于视图的解决方案需要UNION-ALL,而不使用这样的视图需要将UNION-ALL放在任何地方,或者使用某种"看这里,然后看那里"的逻辑应用程序,我说:blech.
简而言之,这是一个设计选择; 我不确定是对还是错.