2010-10-15 78 views
1

嘿,所以这里有一个设计问题:日志表中的外键

我正在处理一个项目,需要我跟踪用户何时执行插入,更新或删除。我试图决定的是,是否让日志表引用受影响的行的主键或其他标识符。为了在使用外键时记录删除,我需要为每个表都设置一个删除列。但是,如果我使用某个没有外键的命名标识符,我最终会在Logs表中运行名称重复,并且它将变得不清楚该条目引用的内容。有没有人有这方面的实际经验,特别是使用删除列以保持完整日志的性能影响?

一个相关的问题也是在日志表本身的设计中。如果我在单个日志表中使用外键引用,那么我的第一个直觉就是为每个正在监视变化的表创建一个引用列。这对我来说并不理想,因为如果我必须添加一个新表,我必须更改日志表和任何关联的sprocs。我可以看到的另一种选择是有两列,TableName和RowId。但是这将没有固有的外键引用,因为它不知道引用了什么表。

感谢您的任何意见!

+1

删除的标志/列被称为逻辑删除。使谈话更轻松。 – 2010-10-15 19:42:01

回答

1

RE:一个日志表,而不是影子表。

虽然这将会有更多的工作,但你不会从中得到太多的帮助。 - 加布里埃尔麦克亚当斯

我不能不同意更多。

你的目标是:

保持当用户执行插入,更新的轨迹,或删除。

如果你对每个表影子表你怎么回答这些问题:

  1. 哪些用户昨天所做的更改?
  2. 什么表有最新更新?
  3. 员工=“Page,S”上个月做了什么活动?
  4. 什么雇员是最活跃的?

你必须通过每个单独的阴影表来弄清楚。如果你开始记录一个新的表格,你必须记得改变这些sprocs来打这个新的影子表格。

如果您有其他人建议的日志表,那么您可以使用简单的SQL轻松回答所有这些问题...... UNIT DELETE或UN-UPDATE最难做的是什么。但是你并没有为此构建它,你正在构建它来跟踪用户的编辑,并且我列出的查询或类似的查询将成为你的面包和黄油。

关于逻辑删除。

如果该表是您无法从其他表中删除的父表,那么它们可能很有用。像员工和工资单一样。您不能删除必须由法律保存的工资记录的员工。如果这就是为什么你在逻辑上删除,很好。但是,如果你在逻辑上删除,以便你将PK保留在日志表中的FK中,那么我认为你买了一个不太好的世界。

如果您有任何代码直接触及这些表格,您现在必须将它们全部更改为包含DELETED ='F'谓词。如果你从头开始,你可以为嵌入DELETED ='F'谓词的每个逻辑删除表创建一个视图,并且从不授予对表本身的选择。

+0

我准备暂时设置单个日志文件。正如你所提到的,对我来说,了解对你列出的问题的答案更重要。 – rpf3 2010-10-22 13:25:26

0

难道你不需要日志表中的四列吗? UserIdTableNameIdAction

Action将被“删除”,“更新”或“插入”,Id将成为有问题的表的主键,其余的,自我解释。

这样你不必拥有大量的列和外键,这只会使插入到日志表中的速度变慢。无论如何,您需要使用触发器来完成此操作,因此将表名添加到日志表中不会成为问题。

+1

-1 - 这不会显示更新的列,并且您将丢失任何删除信息 – 2010-10-15 16:46:02

+1

@Gabriel McAdams,我没有注意到这是一项要求。 – 2010-10-15 16:48:09

0

假设您正在跟踪的每个表的日志信息都是相同的,我将使用带有TableID和RowPKValue列的单个日志表。的确,您无法将RowPKValue FK返回到每个单独的表,但由于日志表永远不会被用户(或LogS以外的任何代码)触及,所以我认为这是相当安全的。

我肯定会使用行记录的PK值而不是任何其他值(即使您没有FK引用它),因为这是PK值的用途。

至于DELETE问题,我认为这取决于1)您希望执行的DELETE的数量,以及2)您将不得不将特征“Undelete”作为应用程序的一部分进行特征化的可能性。

如果您的DELETE数量相对较少,您可以将它们保留在表格中并带有已删除的标记,然后在某个指定期限结束时将其删除。如果你这样做,我推荐一个基本表被称为CustomerAll的方案,并且前台程序员可以使用单个表视图CREATE VIEW Customer AS SELECT * FROM CustomerAll WHERE Deleted = false

如果你有大量的DELETE,我会将它们在DELETE时移动到第二个表(CustomersDeleted)或甚至在数据库外,这取决于你认为它有多可能需要查看它们再次。

1

首先,根据行数和您拥有的索引类型,添加删除的列可能会更好,然后删除该行。第二,我认为最好的选择是将整个行存储在日志表中(这也允许记录任何更新)。你也可以用更规范化的记录表做到这一点 - 是这样的:

  • ID
  • 行动
  • EffectedColumn
  • 的OldValue
  • 的NewValue

这将是一个很大更多的工作,但是,你不会从中得到很多。我建议你将所有数据存储在一张重复的表格中 - 用附加的列显示所采取的行动。

至于对行标识符或其他值的引用,将会有相同的问题,但是你做到了。为了确定哪一行受到影响,同一行中必须存在相同的唯一值。只要该行被删除,那么该唯一值(GUID(t-sql中的uniqueidentifier) - 顺便说一句就是一个选项)。

+0

+1 - 特别针对重复的表格建议。虽然它可能会增加桌子,但我认为它根本不是一个不好的选择! – InSane 2010-10-15 16:55:35

0

也可以使用2表日志文件设置。

洛加 - LOG_ID,表名,动作,DATE_TIME

LogB - LOG_ID,table_id的,columnchanged,OLD_VALUE,NEW_VALUE

(编辑calrify, 'table_id的' 上面是指无论是在你的主键多个PK可能需要多个字段)

在new_value字段中使用空值来表示旧值中的删除和空值以表示插入。

如果您希望避免每个表上的“已删除”列,您可以创建一个已删除的表来存储哪些行被删除,并且使用一个视图来仅显示活动记录(没有自己的unqiue的IE记录删除表内的键)。

将会有很多的这种设计有效的办法......