4

我有一个可以更新各种字段的表。让我们调用它table1并假设它具有以下字段:

user VARCHAR2
first_name VARCHAR2
last_name VARCHAR2

我的问题:我想跟踪对这些字段的编辑。我有一个允许更新这些字段的应用程序,但我想跟踪何时编辑字段、编辑了该字段以及编辑了哪个字段——是我需要帮助的地方。

我可以有一个历史表:

date_edited DATE
who_edited VARCHAR2
field_name_edited VARCHAR2

如果字段名称发生了变化怎么办?...这意味着field_name_edited它将引用一个不存在的字段。这似乎是一种愚蠢的做法。

必须有一些常见的方法来做这种事情吗?

非常感谢。

编辑

我正在使用 Oracle DB - 查看新的问题标签。

4

2 回答 2

6

“一定有一些常见的方法来做这种事情?”

不是真的,因为你的方法是一种常见但被误导的方法。由于以下几个原因,无法在列级别跟踪更改:

  1. 当更新涉及多个列(为每个更新的行插入多个审计记录)时,它会变得很昂贵。
  2. 很难在给定的时间点组装一个连贯的记录状态图(程序复杂,启动成本更高)。
  3. 没有优雅的方法来测试给定列是否已更改。
  4. 存储列值很麻烦(实现通常通过将它们转换为字符串来处理不同的数据类型)。

(您建议的表格没有处理最后一点,我认为这是一个疏忽:不跟踪更改值的审计跟踪几乎没有价值)。

那么,常见的解决方案是什么?行级历史表。使用将整个记录插入日志表的触发器(连同 DATE_EDITED 和 WHO_EDITED 等元数据列)。这些触发器可以很容易地从数据字典中生成。

确实,这种方法使发现在任何给定事务中编辑了哪些列变得更加困难。然而:

  1. 很难但并非不可能做到这一点。它可以在 SQL 中实现(使用分析 LAG 或其他东西),但实际上人类非常擅长在没有帮助的情况下发现变化。
  2. 这样做的成本是由审计子系统承担的,在现实生活中——不管要求怎么说——它不会被太多使用,而且肯定比应用程序的核心部分少得多。因此,最好将处理成本转移到审计子系统上,而不是让日志记录变得昂贵。

而且,正如我所说,行级日志在生成审计记录和检索它们方面的成本都低于列级。


在您的评论中,您链接到有关 Oracle 的Total Recall 产品的文章。这实际上是一个非常优雅的解决方案,它对主系统的影响非常小,并且可以很容易地恢复我们表的历史状态。问题是,在 12c 之前,企业版需要额外收费,这使得它变得昂贵。(事实上​​,它现在是Advanced Compression 选项的一部分,而不是单独的产品)。在 12c 中,Basic Flashback Data Archive(Total Recall 的新名称)在所有版本中都可用,但我们仍然需要购买 Advanced Compression Option 来压缩日志表。


“您建议 [存储] 行编辑,从而存储冗余数据。”

是的。这些天存储通常很便宜。存储冗余数据的成本通常是为高效写入和检索记录而付出的好代价。

“您仍然需要复制原始列的文字名称”

Journalling 为每个数据表使用一个审计表;审计表与实时表的结构相匹配,还有一些额外的列来保存与事务相关的元数据。我们希望审计列与其类似的数据列具有相同的名称。(做任何其他事情都是愚蠢的,尤其是因为我们可以从数据字典中为审计表生成 DDL。)

于 2012-11-04T14:49:28.393 回答
0

免责声明这是我几年前用于类似情况的方法。那时我不太喜欢我们必须做的所有连接和触发器。如果有人有更好的方法,请发布!

据我了解,如果您认为字段名称可能会更改,您应该有一个主数据表来跟踪字段信息。您需要一个用于主数据的历史记录表和一个用于实际用户表的历史记录表。就像上面的一张海报所说,当其中一个表被修改时,您可以使用触发器写入正确的历史表。

table editable_fields

id
field_name
created/modified_by/date

示例条目 = {(1, user), (2, first_name), (3, last_name)}


table user

id
field1_value
field2_value
field3_value
created/modified_by/date

样本条目 = {(1, johnsmith, John, Smith), (2, janedoe, Jane, Doe)}


table user_fields_mapping

id
-- FKs to editable_fields.id
field1_editable_id
field2_editable_id
field3_editable_id

样本条目 = {(1, 1, 2, 3), (2, 1, 2, 3), (3, 1, 2, 3)}

于 2012-11-04T13:47:09.193 回答