【问题标题】:One log table vs log columns on every table一个日志表与每个表上的日志列
【发布时间】:2009-09-23 12:50:43
【问题描述】:

我将插入和更新信息记录到每个表中

create_date    TIMESTAMP
create_user_id INT
update_date    TIMESTAMP
update_user_id INT

我认为与其将它们放在每个表上,不如只创建一个日志表并在每个表上引用日志表,这样我就可以仅在需要时检索日志信息。我知道这取决于应用程序(我正在开发一个小型商业 ERP 之类的应用程序),但是您有这种类型的表的经验吗?任何性能、维护问题?你喜欢哪个?谢谢。

log_id         LONG
create_date    TIMESTAMP
create_user_id INT
update_date    TIMESTAMP
update_user_id INT

编辑:我总结了一个解决方案,即在每个表上仅使用 update_date (插入将被视为更新,不会删除数据,只是停用)和 update_user_id 列。我使用 MySQL,在生产环境中会有主服务器和从服务器。如果发生任何情况回溯数据,我会在从服务器上使用复制日志来审计数据的变化,这样设计更简单,审计虽然不容易。

【问题讨论】:

    标签: database database-design


    【解决方案1】:

    如果在进行任何其他写入的同时写入单个日志表,则很容易成为瓶颈。

    您也会为某些查询生成额外的 JOIN。

    在我看来,我没有看到单独表的好处,除了让其余的数据库表更“干净”

    【讨论】:

    • 使用单独的表,您可以记录每笔交易,而不仅仅是第一笔和最后一笔。但我看到这个问题不建议这样做,我觉得很好奇。
    • recursive:历史数据不会被频繁使用,并且比较每周备份提供了某种记录每笔交易的功能,尽管它更难。
    【解决方案2】:

    单个日志是一件很棒的事情。

    在每个表上,都有一个 ID 列,仅用于记录目的。叫它 LOG_ID 什么的。

    无论您何时执行 INSERT、UPDATE 或 DELETE,它都会像这样工作。

    1. 插入日志条目,获取分配的 LOG_ID。

    2. 执行 INSERT 或 UPDATE,在更改的行上设置 LOG_ID 外键。对于 DELETE,您有两个选择:实际删除该行或将该行标记为“非活动”但实际上不删除它。这第二个选择使您的所有更改日志完全完整,但由于必须跳过不活动的行,使您的表变得非常大而且速度很慢。

    3. 提交。

    确保您的日志设计可以包含以下类型的信息。

    1. 数据库行更改(插入、更新、删除)。插入和更新更改将在某处具有对更改行的 FK 引用。确保包含表名,以便应用程序可以正确定位表。删除更改将只有一个表名。

    2. 批处理作业运行等其他处理信息。这样您就可以记录批处理作业的开始/停止和运行时间,并保留完整的处理历史记录。

    【讨论】:

    • Lott 如果用户更新多个列,你如何处理它?您是否将每个更新的列记录到不同的行。
    • 原设计没有记录栏目变化。为什么要将它添加到这个设计中?记录完全相同的信息:更改日期和用户名。
    • 是的,原始设计不这样做。实际上对于单个日志表,我的计划是每行只保留一个记录。如果用户更新任何行,则它的 log_id 是指单个日志表的单行以及使用时间戳和用户 ID 更新的关联行。当您提到包含表名类型的修改时,我猜您将值与它们一起存储。我提出的设计不包括我上面显示的任何这种模式。无论如何感谢您的回复。
    • @Gok Demir:不要更新日志。插入。对于给定的表,您可以找到所有修改。对于给定的行,您还可以找到修改的历史记录。
    【解决方案3】:

    大约 20 年前,我了解到处理此类信息的最佳方法是向数据库中插入数据。您不应该修改现有记录,也绝对不应该删除任何记录。基本上,您要存储的不是数据本身,而是对数据的修改。因此,只要您有足够的 CPU/磁盘速度来遍历所有数据以仅根据这些插入计算数据,您最终将得到一个可以执行您想要的所有操作的表。

    仅存储修改将让您保留所有数据的完整历史记录,让您非常灵活。基本上,您只需要一张包含所有内容的表格。缺点是你需要做更多的计算并且需要更多的磁盘读取,所以你需要一些技巧来加快这个过程。以性能为代价的灵活性...

    在这种情况下,您最终会遇到类似的问题。任何需要添加或更新记录的东西都可以访问单个表。这将是你的瓶颈。它在单用户环境中仍然很棒,因为只有一个用户会使用它。在低用户环境下,它仍然可以有很好的性能。但如果您有 250 多个用户一直在访问此表,则会降低整体性能。

    另外,当有人删除记录时,您会引入维护问题。在这种情况下,该日志表中的记录也需要删除。

    让我回到我在开头提到的事情......您可以做的是将历史表和常规表结合起来。每当插入、修改或删除一条记录时,您都会将一条记录添加到此修改表中,包括时间戳和用户引用。这将维护您的数据的历史记录,一般来说,您只会在此表中进行插入操作。这应该仍然很快。作为额外的奖励,您可以通过重播此修改表中的所有操作来重新创建数据库的全部内容,以防万一。

    插入可以相当快,因此性能损失相当小,但这取决于您的实现。

    但无论出于何种原因,在学习了使用修改表之后,我从来没有遇到过可以使用这种技术的实际情况。

    【讨论】:

      【解决方案4】:

      我们通常在大多数桌子上使用这些:

      LastChgID      int
      LastChgDate    datetime
      

      有时会用,这个就几个:

      CreateID       int
      CreateDate     datetime
      LastChgID      int
      LastChgDate    datetime
      

      还有一个完整的镜像表,我们在其中记录每一列,其中包含更改类型标志、日期时间和用户 ID。

      我会远离您一直更新的表,只需添加列,这就是数据库的用途,以存储信息。我们有一个表,每次调用存储过程时都会增加(更新),这是一个死锁磁铁。

      我们确实有一个通用日志表,但它只是插入的,并且包含调试和错误信息。它不会在每次更改任何行时都更新,只有当开发人员决定在那里写一些东西时,主要是一些标题字段(身份、日期时间、用户 ID、调用自的过程)以及包含消息的长格式字符串。

      【讨论】:

      • 死锁磁铁。是的,这是要考虑的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-08
      • 2015-06-28
      • 1970-01-01
      • 2013-05-14
      • 2015-01-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多