将冗余信息插入数据库以防止表连接?

时间:2014-06-27 18:39:43

标签: mysql sql

我正在尝试构建一个具有以下结构的活动流:

------------------------------------------------------------------------------------
id | activity_by_user_id | activity_by_username | ... other activity related columns
------------------------------------------------------------------------------------

这是在活动表中存储 activity_by_username 的好方法吗?我知道这会一次又一次用相同的用户名混乱。但如果没有,我将不得不与users表进行联接以获取用户名。

我的网络应用程序中的用户名永远不会改变。

有了这个,我将不再需要将此表与users表连接。这是实现我需要的最佳方式吗?

4 个答案:

答案 0 :(得分:2)

您建议的是对数据结构进行非规范化。这种方法有利有弊。

显然,您认为性能将是一个优势,因为您不需要在每一行上查找username。这可能不是真的。查找应该在表的主键上,并且应该非常快。甚至存在存储冗余信息可能减慢查询的情况。当字段大小很大并且有许多应用程序具有相同用户时,会发生这种情况。然后,您在冗余数据上浪费了大量存储空间,从而增加了表的大小。但是,通常情况下,您可能会看到适度 - 非常适度 - 的性能提升。

与此平衡的是您正在存储冗余数据。因此,如果更新了用户名,则必须使用新信息更改许多行。

总的来说,如果您在环境中对实际数据进行测试,我建议您采用这种方法,性能提升是值得的。我怀疑你会看到很多改进,但证据就在于布丁。

顺便说一下,有些情况下需要使用非规范化数据结构来支持应用程序。我不认为使用主键查找字段可能是其中之一。

答案 1 :(得分:2)

您的问题 *

没有单一的答案

通常,关系数据库设计旨在避免冗余以限制数据异常的机会。例如,您现在有可能两个给定的行可能包含相同的用户ID但用户名不同。哪一个是正确的?你如何防止这种差异?

另一方面,通过冗余地存储某些列来进行非规范化有时是合理的。你是对的,你因此避免加入。但现在您有责任确保数据异常不会蔓延。

这真的值得吗?在MySQL中,通过主键查找相关行的连接非常有效(在EXPLAIN中,您将此视为连接类型" eq_ref")。我不会尝试解决这个问题,直到你能证明它是一个瓶颈。

基本上,非规范化优化了一种类型的查询,但代价是其他类型的查询。您在预防,检测和纠正数据异常方面所做的额外工作可能比在这种情况下避免连接所获得的任何效率更高。或者,如果用户名有时会发生变化,您现在必须在两个地方更改它们(我知道您说用户名不会在您的应用中发生变化)。

重点在于它完全取决于您的应用程序运行不同查询的频率,因此并非任何人都可以为您解答。


  

*这也许可以解释为什么有些人会贬低你的问题 - StackOverflow中的某些人似乎对什么是有效的"有一个相当严格的想法?题。我已经看到问题被关闭甚至被删除,因为它们过于主观和基于意见。但我也看到问题被删除,因为答案太明显了#34;我的一个answers with 100 upvotes丢失了,因为主持人认为问题是“如果我单独工作,我真的需要版本控制吗?”#34;无效。去搞清楚。我将其复制到我的博客here

答案 2 :(得分:1)

我认为这是个坏主意。数据库针对连接进行了优化(假设您完成了工作并正确编制了索引),并且非规范化数据非常难以维护。现在可能没有用户名更改,但您可以保证将来没有。在这样的事情上冒险你的数据完整性充其量是短视的。

仅在存在性能问题且其他优化技术无法改善情况的极少数情况下进行非规范化。非规范化甚至不会总能让您获得任何性能提升。随着表格越来越广,它甚至可能会降低性能。所以不要这样做,除非你有一个可衡量的性能问题,你测量并确保denormlaization实际上有帮助。这是尝试所有这些技术的最后一种优化技术,所以如果你没有在非常大的可能性列表中完成所有的优化技术,那么首先,非规范化不应该是一种选择。

答案 3 :(得分:1)

没有。这违反了数据规范化的所有原则。

它甚至不会那么困难(如果我正在解释你的意思是id,user_id和user_name); id将是将所有东西捆绑在一起的主键 - 以及JOIN的关键。因此,您将拥有包含id,其他活动col,下一个活动col等的主表(不确定您的活动是什么意思)。然后是第二个表,只有id和user_id,第三个表有id和用户名)。当你想要输出你要输出的任何内容,并通过user_id或username进行输出时,你只需要JOIN(隐含的连接语法 - WHERE table1.id = table2.id)。