哪个效率更高:多个MySQL表还是一个大表?


103

我在MySQL数据库中存储了各种用户详细信息。最初,它是在各种表中设置的,这意味着数据与UserId链接,并通过有时复杂的调用输出,以根据需要显示和操作数据。设置一个新系统,将所有这些表组合成一个大的相关内容表几乎是有意义的。

  • 这将是帮助还是阻碍?
  • 调用,更新或搜索/操作时的速度考虑?

这是我的一些表结构的示例:

  • 用户-用户ID,用户名,电子邮件,加密的密码,注册日期,IP
  • user_details-Cookie数据,姓名,地址,联系方式,从属关系,人口统计数据
  • user_activity-贡献,最近一次在线访问,最后一次查看
  • user_settings-配置文件显示设置
  • user_interests-广告可定位变量
  • user_levels-访问权限
  • user_stats-匹配数

编辑:到目前为止,我已经对所有答案进行了投票,它们都有本质上可以回答我问题的元素。

大多数表具有1:1的关系,这是使它们归一化的主要原因。

如果表格跨越100多个列,而这些单元格的大部分可能仍为空时,会不会有问题?


这个问题也可能会有所帮助
Mosty Mostacho

Answers:


65

多个表以下列方式/案例提供帮助:

(a)如果不同的人要开发涉及不同表的应用程序,则将它们拆分是有意义的。

(b)如果您想为不同的人赋予不同的权限,以进行数据收集的不同部分,则将它们拆分会更方便。(当然,您可以查看定义视图并对其进行适当授权)。

(c)对于将数据移动到不同的地方,尤其是在开发过程中,使用表来减小文件大小可能是有意义的。

(d)当您在单个实体的特定数据收集上开发应用程序时,较小的占地面积可能会给您带来舒适感。

(e)这是一种可能性:您认为作为单个值的数据将来可能会变成真正的多个值。例如,信用额度到目前为止是单个值字段。但是明天,您可能会决定将值更改为(日期,日期至信用值)。拆分表现在可能会派上用场。

我的投票将是针对多个表-数据已适当拆分。

祝好运。


3
@RohitKhatri:据我所知,拥有多个表在大多数情况下会提高性能。
Hari Harker

1
@HariHarker感谢您的回答,但我发现这取决于您的访问方式。
罗希特·哈特里

直到最近,我始终将所有数据存储在一个表中,但想到它,在性能(取决于课程的用例),语义(将某些数据更好地分组到一个表中)方面拆分数据具有很多优点。不同的表格)和开发。例如,我现在正在遗留系统之上开发定制的ERP系统。我不得不用额外的列来扩展旧的数据库表。我决定为新数据创建新表。一些新功能可用于旧系统,现在我可以轻松地集成它们,而不必重写过多的旧查询
Ogier Schelvis

35

合并表称为非规范化。

可能会(也可能不会)帮助使某些查询(使很多JOINs)更快地运行,而以创建维护地狱为代价。

MySQL只能使用JOIN方法,即NESTED LOOPS

这意味着对于驱动表中的每个记录,MySQL在循环中在驱动表中找到匹配的记录。

查找记录是相当昂贵的操作,可能需要花费纯记录扫描数十倍的时间。

将所有记录移到一个表中将帮助您摆脱此操作,但是表本身会变大,并且表扫描需要更长的时间。

如果其他表中有很多记录,则表扫描的增加可能会增加按顺序扫描记录的好处。

另一方面,可以保证维护。


1
如果您有10000个用户,并且正在正确连接使用外键设置的数据库,则只需执行类似select * from name =“ bob”的用户这样的操作即可进行密集查找。一旦有了bob,就可以使用索引来查找要连接到bob的表,因为使用bob的ID会大大加快连接速度。无论您要在查询中进行联接还是查询bob然后分别查询表,都会发生这种情况。当然,希望您的第二个查询基于bob的ID,而不是其他内容。
鲁迪·加西亚

17

他们都是1:1的关系吗?我的意思是,如果某个用户可能属于不同的用户级别,或者如果用户兴趣在用户兴趣表中表示为多个记录,那么合并这些表将立即成为问题。

关于以前关于规范化的答案,必须说数据库规范化规则完全忽略了性能,只看什么是整洁的数据库设计。这通常是您想要实现的目标,但是有时为了追求性能而积极地规范化是有意义的。

总而言之,我要说的问题归结为表中有多少个字段以及访问它们的频率。如果用户活动通常不是很有趣,那么出于性能维护的原因,始终将其保留在同一记录上可能会很麻烦。如果经常访问某些数据(例如设置),但仅包含太多字段,则合并表可能也不方便。如果仅对性能提高感兴趣,则可以考虑其他方法,例如将设置分开,但将其保存在自己的会话变量中,这样就不必经常查询数据库。


我必须完全不同意您的意见,即规范化仅关注整洁而完全不考虑性能。两种方案都需要权衡取舍,反规范化实际上会使数据完整性受到威胁。我想说,对数据库进行规范化实际上可以提高数据库的整体性能,而不是使非规范化表的性能迅速提高,可以忽略不计。
鲁迪·加西亚

鉴于讨论专门针对1:1关系,所以拆分表不是规范化任务,对吗?如果没有重复的信息,即使是单个表也是如此。(好吧,它可能不满足3NF规范化,因此受益于第二张表来解决该问题,但这似乎不是OP指的是其他表。)
ToolmakerSteve19年

14

难道所有这些表都一个1-to-1关系?例如,将每个用户的行只需要在一个相应行user_statsuser_levels?如果是这样,将它们组合到一个表中可能很有意义。如果不是 这种关系1 to 1,则将它们组合(去规范化)可能没有意义。

将它们放在单独的表中而不是一个表中可能对性能几乎没有影响,除非您有成千上万的用户记录。您将获得的唯一真正收获是通过组合查询来简化查询。

预计到达时间:

如果您的关注是关于有太多的列,然后想想什么东西,你通常使用起来并结合这些,(如果需要的话或几个单独的表),留下其余的在一个单独的表。

如果您查看数据的使用方式,我的猜测是,您会发现大约80%的查询使用20%的数据,而其余80%的数据仅偶尔使用。将经常使用的20%合并到一个表中,然后将不经常使用的80%留在单独的表中,您可能会做出很大的妥协。


是的,每个表的每个用户只有一行,这只是为了避免管理大量重复数据的麻烦。这就是为什么我在考虑一张桌子适合。如果用户数据跨越多行,我希望这些表与主用户表分开。
彼得·克雷格

1
如果每个表具有1到1的关系,则一个表将更易于使用。在这种情况下,无需拆分表。拆分表可能会暗示有多于1行,这可能会导致另一位开发人员以这种方式对待它们的情况。
理查德L

将80/20应用于数据库表设计的想法非常有趣。让我也思考OOP(我主要是Java开发人员)类设计,并想知道那里是否有效(将80%的主要应用程序功能放在一个类中,其余的放在其他类中)。
Zack Macomber '18年

1
@ZackMacomber-不,分类应该基于引用的位置。分成多个类的好处是在较小的功能单元周围画了一条边框,以便更容易理解/测试/更改,并弄清楚该单元与其他功能单元的交互位置。目标是将大多数连接(引用,调用)保持一个单元内,而单元之间的连接很少。定义类实现的几个接口(每个用例具有不同的接口)可能是实现拆分的有用的第一步。
ToolmakerSteve

@ToolmakerSteve好想法+1
Zack Macomber

9

创建一个大表违反了关系数据库的原则。我不会将所有这些组合到一张桌子中。您将获得多个重复数据实例。例如,如果您的用户有三个兴趣,则您将有3行,其中相同的用户数据仅用于存储三个不同的兴趣。肯定要使用多个“标准化”表方法。见对数据库标准化Wiki页面。

编辑: 我已经更新了我的答案,因为您已经更新了您的问题...从现在开始,我现在甚至更多地同意我的最初答案。

这些单元格的很大一部分可能仍为空

例如,如果某个用户没有任何兴趣,那么如果您进行归一化,那么您就不会在该用户的兴趣表中出现一行。如果您将所有内容都放在一个庞大的表中,那么您将拥有仅包含NULL的列(显然有很多列)。

我曾在一家电话公司工作,那里有大量的表格,要获取数据可能需要很多联接。当从这些表中读取数据的性能至关重要时,则创建可以生成平面表(即非规范化表)的程序,该程序将不需要连接,计算等报告即可指向。然后将这些与SQL Server代理结合使用,以一定的时间间隔运行该作业(即每周一次查看某些统计信息,每周运行一次,依此类推)。


我喜欢这种方法,因为非规范化的数据只是作为瞬间快照而临时存在。没有插入/修改/删除问题-完成后将其丢弃。
制造商史蒂夫

7

为什么不使用相同的方法,Wordpress通过让一个用户表具有每个人都拥有的基本用户信息,然后添加一个“ user_meta”表,该表基本上可以是与用户ID相关联的任何键,值对。因此,如果您需要查找用户的所有元信息,则可以将其添加到查询中。如果不需要诸如登录之类的东西,您也不必总是添加额外的查询。这种方法的好处还使您的表可以向用户添加新功能,例如存储其Twitter句柄或每个个人兴趣。您也不必处理关联ID的迷宫,因为您有一个可以管理所有元数据的表,并且将其限制为仅一个关联而不是50个关联。

Wordpress专门这样做是为了允许通过插件添加功能,因此允许您的项目更具可伸缩性,并且如果您需要添加新功能,则不需要彻底的数据库检查。


WordPress wp_usermeta表格以几何形式增长。每个用户向wp_usermeta表中添加X行,对于我们要为该用户保留的每条元信息,一行。如果为每个用户保留8个自定义字段,则意味着wp_usermeta将为users * 8行长。这似乎是造成性能问题的原因,但是我不确定这是否是问题所在……
thirdender 2014年

1
我可以看到,如果您有成千上万的用户,这可能会导致性能问题。基本上,数据库将必须在用户元表中搜索10000 * 8条目以找到您要查找的条目。但是,如果仅在需要时查询元数据,我认为您的性能会更好。如果即使在不需要元数据时也一直在请求元数据,则可能会遇到问题。如果您始终需要元数据,那么拆分表并不是最佳方法。
Rudy Garcia

1
就在昨天,我们处理了一个WP主题,该主题正在加载所有用户(使用get_users())只是为了计算分页。一旦我们更正了代码以使用SELECT COUNT(…)查询进行分页,页面加载时间就从28秒缩短到了约400ms。我仍然想知道性能与联接表或单个平面表相比如何……我在查找网络上的任何性能指标时遇到了麻烦。
第三方2014年

考虑我之前的评论,似乎除非有某些原因(例如上述分页示例)需要选择所有用户,否则拆分表似乎仍然有效。尽管如果要检索所有元信息,则usermeta表中仍将有80k条目。要搜索的东西很多。也许有人可以通过在两个实现上运行脚本并运行100次以获得平均值来测试哪种方法更好,我可能只是这样做。
2014年

1
直到今天,我才重新阅读了这篇文章,并意识到我对10000 * 8条目的评论是正确的,但是数据库的工作方式应该使其几乎没有问题。如果由于某种原因您要抢走所有10000个用户,然后又抢走他们的元信息,那将是荒谬的。我想不出任何想要的方案。由于外键和索引的关系,数据库将轻松以闪电般的速度检索单个用户的元数据。假设您的数据库模型设置正确。
鲁迪·加西亚

5

我认为这是“取决于情况”的情况之一。拥有多个表更干净,理论上可能更好。但是,当您必须联接6-7个表以获取有关单个用户的信息时,您可能会开始重新考虑这种方法。


1

我要说的是,这取决于其他表格的真正含义。user_details是否包含多于1个/用户,依此类推。标准化的哪个级别最适合您的需求取决于您的需求。

如果您的一张表的索引很好,那可能会更快。但是另一方面,维护起来可能更加困难。

在我看来,您可以跳过User_Details,因为它可能与Users是一对一的关系。但是其余的每个用户可能有很多行?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.