这是一个设计问题。
假设我有一个用户表 {UserKey, UserName} 并且我正在记录一些用户活动。所以在日志表 {UserKey, Activity} 中,我有一个 UserKey 列。现在将日志表中的 UserKey 作为用户表的外键是不是一个好主意?
据我所知,
优点(ForiegnKey):没有悬空记录。
缺点(ForiegnKey):除非我也删除日志,否则无法进行硬删除,这显然很糟糕。
你的建议是什么?我还缺少什么?
这是一个设计问题。
假设我有一个用户表 {UserKey, UserName} 并且我正在记录一些用户活动。所以在日志表 {UserKey, Activity} 中,我有一个 UserKey 列。现在将日志表中的 UserKey 作为用户表的外键是不是一个好主意?
据我所知,
优点(ForiegnKey):没有悬空记录。
缺点(ForiegnKey):除非我也删除日志,否则无法进行硬删除,这显然很糟糕。
你的建议是什么?我还缺少什么?
缺点(ForiegnKey):除非我也删除日志,否则无法进行硬删除,这显然很糟糕。
首先,这并不是“明显”坏的。这只是处理悬空记录的一种方法。顺便说一句,您不必从客户端代码中执行此操作 - 您可以通过 ON DELETE CASCADE 引用操作将其自动化,并让 DBMS 为您执行此操作。
另一种方法是拥有一个 NULL-able FK(并且可能使用 ON DELETE SET NULL)。
您根本无法保留与数据库中不再存在的用户关联的记录。悬空记录可能会保留用户密钥,但该密钥不再有意义,甚至可以被新用户重用(如果您使用自动递增 ID,则不太可能,但仍然可能)。
但是您可以“退休”用户(例如,通过在用户表中设置一个标志)并仍然保留她的所有记录,并且可能有一个后台进程来清理那些太老而不再重要的退休用户。
无论如何,FK 是防止悬空记录的方法,我非常不愿意放弃它。通过正确的索引,应该没有性能问题,如果您认为有,请在做任何其他事情之前测量并确认它确实存在......
我建议 no-FK (1) 虽然我们可以创建 FK 关系,但它不一定是真的关系。意思是说,一个用户有很多用户事件......事件有一个单独的目的,这并不是很有意义。(2) 我们可以允许匿名/访客用户,他们也应该记录事件!
正如您自己所见,这两种方法各有利弊。就个人而言,我不喜欢将外键放在日志表中,因此您写入表的唯一时间是追加新记录时,并且可以针对追加优化日志表的存储。作为一项好处,您可以使用原始 ID 维护有关已删除项目的日志记录。
缺点(ForiegnKey):除非我也删除日志,否则无法进行硬删除,这显然很糟糕。
物理删除Users
但不删除日志?我认为这样的概念需要重新思考和优先考虑。
在删除之前,我会hide
考虑user
.
否则,如果您不知道谁做了什么,那么保留日志的意义何在。
如果不是删除users
你归档它们,FK 并不是真正的检查 FK,而只是一个建议。
您的问题有多种解决方案。您可以1. logically delete
用户并保持数据完整,也可以2. log the user key only
在日志表中。
如果您有少量/中等数量的用户,第一个解决方案非常好。但它有性能上的缺点:如果应用程序增长并且用户数量变大,那么在用户表中仍然会有不活跃的用户,这些记录会减慢数据库响应(例如,在登录操作期间) .
第二种解决方案很好,无论您的应用程序在一段时间内拥有多少用户。但是您将丢失已删除用户的数据。因此,您将不知道 5 年前进行某些活动的已删除用户的详细信息。
还有第三种方案:3. using table 'UserArchive'
这个方案结合了第一种方案的优点,避免了第二种方案的问题。您可以构建一个名为 UserArchive 的新表,该表将包含应用程序中存在的所有用户的数据。将 Log 表与 UserArchive 表链接可以为您提供每个用户的数据,即使该用户不再存在于 Users 表中,也进行了一些活动。
当用户注册时,您可以在 Users 表中添加所需的详细信息,并在 UserArchive 表中添加一些重要(或全部)详细信息。(注意数据冗余,这对您的数据库是好是坏取决于您)当用户想要删除帐户时,您可以自由地在用户表中进行硬删除,因为重要(或所有)详细信息是存储在 UserArchive 中。
建议:Users 表不应该与 UserArchive 连接,因为从逻辑的角度来看它不是必需的。
哪种解决方案最适合您的应用取决于您自己。