使用自然密钥,或使用代理键和审计表进行审计/更改日志

时间:2009-08-17 06:52:54

标签: database-design denormalization audit-trail

我在这里的第一个问题很好!

我是一名经验不足的初级开发人员,我遇到了这个问题。

我有一张需要审核的表格。假设这张桌子记录了呼叫中心拨打的电话(不是,但这只是一个例子)。我称之为“CallHistory”。

我最初计划保留一个名为“被叫”的单独表格,其中包含被叫方的姓名,电话号码等。此表格将使用代理主键。

CallHistory表将具有Callee表的外键。

我最初这样做是因为如果我更改了被叫方的电话号码,它会在整个系统中传播,我不必更改多个表格中的电话号码。

问题是,CallHistory表的重点是记录呼叫的HISTORY,包括拨错的呼叫(比如呼叫者拨错了号码)。使用这种替代密钥方法将丢失历史记录。

其中一位高级开发人员建议在CallHistory表中的特定时间保留每次拨打呼叫者的电话号码副本,以保留历史记录。

我正在考虑为同一目的保留审计/更改日志表。

我的方法对于这种清除是否足够,还是我完全偏离轨道?您更喜欢哪种方式?

干杯, 安德鲁

3 个答案:

答案 0 :(得分:2)

我认为你被这里关于正常形式的微妙所误导。问题是,与被叫方关联的电话号码与呼叫方拨打的号码不是同一条信息。它们在一般情况下可能具有相同的值,但这是另一个问题。

所以在我看来,CallHistory应该同时使用numbre dialed和对被调用者表的引用。

答案 1 :(得分:1)

你的问题是非常典型的设计困境。例如,如果您拥有正常形式的数据库,并且您拥有以下表格:销售,经理(销售人员)和地区(经理正在工作)。您正在构建报告,例如“按地区分组的年度销售额”,您可以通过区域与经理和经理一起加入销售。但如果其中一位经理将在一年内搬迁到另一个办公室,那么您的报告似乎会显示不正确的数据,对吗?

3种解决方案是什么

1)在某些情况下,开发人员和分析师决定:好吧,我们的数据不是很正确,但现在可以,我们希望保持正常形式,不要重复数据。该解决方案不太复杂。在这种情况下,您可以以正常形式创建Callers和CallHistory表,即电话号码仅在Callers表中。

2)要求不要丢失任何历史变化。我们希望我们的报告和查询非常快(以数据库大小为代价)。在这种情况下,人们决定复制所有字段。例如,您可以创建具有电话号码,呼叫者姓名,地址等的CallHistory表,因为您预计将来可以更改这些字段中的每一个。当然你也可以创建Callee表(可能你需要它用于其他目的)但它可能会被CallHistory所暗示并且可能不是。假设您认为某些记录需要从Callee中删除,但希望它们位于CallHistory中。当开发人员经常认为他们可以违反数据的参照完整性时,就不会从CallHistory表创建任何外键。这是合理的,因为没有外键,插入操作会更快。

3)方法我更喜欢,但从实现的角度来看它最复杂:CallHistory表应该引用CalleeHistory表。 CalleeHistory表将包含Callee表所具有的所有文件,但它也有一个代理键,如CalleeID + DateModified(有时代替DateModified开发人员使用ModificationVersionNumber)。在CallHistory中,我们有一个引用CalleeID + DateModified的代理外键。在这种情况下,您已经标准化了数据(即电话号码不在不同的表格中公开),而且您也没有丢失任何历史变化。

据我所说,在实现的复杂性,数据库性能,数据库大小,数据完整性和系统的功能要求之间经常需要权衡。如果您是初级开发人员,请记住所有可能的解决方案,但您可能应该倾听高级开发人员的意见,他们比Stack Overflow上的任何人更了解您的系统和需求。

P.S。

如果您想了解其他方法,请参阅有关缓慢更改尺寸的内容,例如http://en.wikipedia.org/wiki/Slowly_changing_dimension

答案 2 :(得分:1)

我同意Rik。是的,冗余数据是非常非常糟糕的,邪恶的,有臭味的,以及其他不受欢迎的数据。但仅仅因为两个字段被称为“电话号码”并不能使它们成为同一个东西。 “客户当前的电话号码”和“我们上次与他交谈时的客户电话号码”不一定完全相同。

我目前正在使用一个保存销售和商品信息的数据库。项目记录包括描述,库存号和价格等信息。我们的销售记录还包括描述,库存号和价格。描述和库存号是多余的,应该删除。这是糟糕的设计。但价格必须包括在两个地方。当前价格与特定销售时的价格之间存在很大差异。这笔交易可能是几年前的。从那时起,价格可能已经变了十几次。

一般情况下,在您描述的应用程序中,我只是将电话号码放在历史记录表中并完成。通过“电话号码历史记录”表并链接到适用的电话号码记录,几乎无法获得。它可能会为每条记录节省几个字节,但会增加一堆复杂性。但是,如果有几个相关领域,则故事会发生变化。如果,而且 - 我只是在这里发明一个例子来表达这个想法 - 你是一家健康保险公司,你的保险条款因地点不同而有所不同,因为州法律不同,该地区的医生等等,因此,当客户移动时,必须重写其策略,现在电话号码可能与许多其他数据项相关,因此所有数据都应该放在一个表中,然后链接到相应的记录。否则你可以拥有新泽西州的电话号码,但是你要链接到加州政策条款等。