我的桌子上有40多个栏目,我需要添加更多的字段,如当前城市,家乡,学校,工作,大学,拼贴画......
这些用户数据将被拉为许多匹配用户,这些用户是共同的朋友(与其他用户朋友一起加入朋友表以查看共同的朋友)以及谁没有被阻止以及谁还不是该用户的朋友。
上面的请求有点复杂,所以我认为将额外的数据放在同一个用户表中以便快速访问是个好主意,而不是在表中添加更多连接,这会使查询速度降低。但是我希望得到你的建议
我的朋友告诉我要添加额外的字段,这些字段不会在一个字段上作为序列化数据进行搜索。
ERD图:
一些建议
答案 0 :(得分:6)
像往常一样 - 这取决于。
首先,有一个maximum number of columns MySQL can support,你真的不想到达那里。
其次,如果你有很多带索引的列,那么在插入或更新时会对性能产生影响(虽然我不确定这在现代硬件上是否重要)。
第三,大型表通常是所有与核心实体相关的数据的倾销场;这很快使设计不清楚。例如,您提供的设计显示3个不同的“状态”类型字段(status,is_admin和fb_account_verified) - 我怀疑有一些业务逻辑应该将它们链接在一起(例如,管理员必须是经过验证的用户),但是设计不支持。
这可能是也可能不是问题 - 它更像是一个概念性的架构/设计问题,而不是一个性能/它是否有效。但是,在这种情况下,您可以考虑创建表以反映有关帐户的相关信息,即使它没有x对多关系。因此,您可以创建“user_profile”,“user_credentials”,“user_fb”,“user_activity”,所有这些都由user_id链接。 这使它更整洁,如果你必须添加更多与facebook相关的字段,它们将不会在表的末尾悬挂。但是,它不会使您的数据库更快或更具可扩展性。连接的成本可能微不足道。
无论你做什么,选项2 - 将“很少使用的字段”序列化为单个文本字段 - 是一个糟糕的主意。您无法验证数据(因此日期可能无效,数字可能是文本,非空值可能会丢失),并且“where”子句中的任何使用都会变得非常慢。
一种流行的替代方案是“实体/属性/价值”或“钥匙/价值”商店。此解决方案具有一些优点 - 即使您的架构发生更改或在设计时未知,您也可以将数据存储在关系数据库中。但是,它们也有缺点:在数据库级别(数据类型和可空性)验证数据很困难,使用外键关系很难与其他表进行有意义的链接,查询数据会变得非常复杂 - 想象一下记录状态为1且facebook_id为空且注册日期大于昨天。
鉴于您似乎知道数据的架构,我会说“键/值”不是一个好的选择。
答案 1 :(得分:1)
我会建议进行一些测试。尝试两种方式并对其进行基准测试。没有人能够给你一个明确的答案,因为你没有分享你的硬件配置,样本数据,样本查询,你打算如何使用数据等。这里有一些你可能想要考虑的信息。
按预期使用数据库
关系数据库专门用于处理数据。这样使用它。正确编写后,在编写良好的模式中加入数据将表现良好。您可以使用EXPLAIN来优化查询。您可以记录SLOW查询并提高其性能。数据库已存在多年,如果将所有内容放入单个表中可以提高性能,难道您认为这不会是互联网上的所有嗡嗡声并且每个人都会这样做吗?
引擎类型
随着行数的增长,插入将如何受到影响?您使用的是MyISAM还是InnoDB?您很可能希望使用InnoDB,因此您获得行级锁定而不是表。确保为表使用正确的引擎类型。获取您需要的信息,以了解两者的优缺点。错误的引擎类型可能会影响性能。
使用分区提升效果
找到提高效果的方法。例如,随着数据集的增长,您可以对数据进行分区。 Data partitioning将通过将数据切片保存在单独的分区中来提高大型数据集的性能,从而允许您对大型数据集的部分内容而不是所有信息运行查询。
使用正确的列类型
考虑使用UUID主键来实现可移植性和未来增长。如果使用正确的列类型,则可以提高数据的性能。
不要序列化数据
使用序列化数据是更糟糕的方法。使用序列化字段时,基本上将数据库用作文件管理系统。它将保存并检索“文件”,但随后您的代码将负责反序列化,搜索,排序等。我只花了一年时间试图解开像这样的混乱。这不是数据库的用途。任何建议你这样做的人不仅会给你不好的建议,也不会知道他们在做什么。在极少数情况下,您可以在数据库中使用序列化数据。
<强>结论强>
最后,你必须做出最终决定。只需确保您了解并了解如何存储数据的优缺点。我要给出的最后一条建议是找出mysql的重度用户在做什么。你认为他们将数据存储在一个表中吗?或者他们是否构建关系模型并按照设计使用的方式使用它?
当你说“我要把所有东西都放在一个表中”时,你说的是你对性能有了更多的了解,并且可以为代码中的优化做出更好的选择,而不是那些经常在MySQL上工作的开发人员团队。它今天是什么。考虑根据MySQL团队以及每天使用它的DBA,公司和数据库社区成员的累积知识来衡量您的知识。
答案 2 :(得分:1)
在某一点上,您应该查看“短行模型”,也称为实体键值存储,以及传统的“长行模型”。
如果查看WordPress使用的架构,您将看到有一个包含23列的表wp_posts和一个包含4列的相关表wp_post_meta(meta_id,post_id,meta_key,meta_value)。元表是一个“短行模型”表,允许WordPress为帖子提供无限的属性集合。
“长行模型”或“短行模型”都不是最好的模型,通常最好的选择是两者的组合。由于@nevillek指出搜索和验证“短行”并不容易,因此获取数据可能涉及在MySql和Oracle中令人烦恼的转向。
“长行模型”更容易验证,关联和获取,但是当数据稀疏时,它可能非常不灵活且效率低下。某些行可能只有少数值为非null。此外,您无法在不修改架构的情况下添加新列,这可能会导致系统中断,具体取决于您的架构。
我最近参与了一个金融服务系统,每个工具有700多个可能的事实,大多数事实少于20个。这可以通过设置几十个表来构建,每个表用于特定的资产类,或者作为一个包含700列的表,但我们选择使用包含最常用事实和4列的约20列表的组合包含其他事实的表格。这种设计很有效但很难访问,所以我们在PL / SQL中构建了一些表函数来帮助解决这个问题。
答案 3 :(得分:0)
我有一般性评论,
考虑一下:如果你在表格中放置超过10-12列的任何内容,即使将它们放入表格中也是有意义的,我想你会在短期,长期和中期付出代价术语
你的3表方法似乎比1表方法更好,但考虑将它们分成5-6个表而不是3个表,因为你仍然可以。
将currently
中的currently_position
,currently_link
,user-table
和work
中的user-profile
移至新表中,主键名为{{ 1}}。
将区域设置信息从USERWORKPROFILE
移至较新的user-profile
信息,因为它本质上是通用的。
是的,所有表中的所有通用属性都应该是USERPROFILELOCALE
而不是int
。
例如,City需要移出一个名为varchar
_ OF_CITIES且LIST
的新表。
您的属性cityid
应从city
更改为varchar
,并指向LIST_OF _ int
中的cityid
。
不要担心性能问题;您拥有的表越多,性能越好,因为您实际上是将性能分发给数据库提供者而不是自己掌握所有这些。