【问题标题】:mysql table with 40+ columns具有 40 多列的 mysql 表
【发布时间】:2013-01-09 09:25:04
【问题描述】:

我的表中有 40 多列,我必须添加更多字段,例如当前城市、家乡、学校、工作、大学、拼贴……

这些用户数据将为许多匹配的用户提取,这些用户是共同的朋友(与其他用户朋友加入朋友表以查看共同的朋友)并且未被阻止并且还不是用户的朋友。

上面的请求有点复杂,所以我认为将额外的数据放在同一个用户表中以快速访问是个好主意,而不是向表中添加更多的连接,这会降低查询速度。但我想听听你的建议

我的朋友告诉我添加额外的字段,这些字段不会作为序列化数据在一个字段上进行搜索。



ERD 图:



一些建议

  1. 这个表和列没有问题
  2. 遵循这种方法MySQL: Optimize table with lots of columns - 将额外的字段序列化为一个字段,这是不可搜索的
  3. 创建另一个表并将大部分数据放在那里。 (如果我已经有 3 个或更多表要加入来为用户(例如朋友、用户、检查共同朋友)提取记录,这会变得更难加入)

【问题讨论】:

  • 在使用连接时,具有引用完整性的正确规范化表模式将为您提供更好的服务... :)
  • 40+ ROWS 与您的问题标题不同 40+ columns... ;) 正如@NevilleK 指出的那样,这取决于即使是完全规范化和完美引用的表可能有 100 多列来描述该实体..
  • @bonCodigo 对不起,我的意思是列
  • 为了您自己的理智,我会选择类似于您的第二个 ERD 的东西:将身份验证与“个人资料”信息分开。如有必要,构建一个可以处理第 3 方登录的结构 - 不一定是您所拥有的特定于 FB 的结构。如果有什么东西适合在您的架构中进行字段粉碎序列化,那么它可能是 3rd 方登录对象,它可以是可变的,通常由 3rd 方库处理,并且通常以 json 或 xml 的形式交付。

标签: mysql sql optimization multiple-columns


【解决方案1】:

像往常一样 - 这取决于。

首先,有一个maximum number of columns MySQL can support,而你并不想去那里。

其次,如果您有很多带有索引的列,则插入或更新时会影响性能(尽管我不确定这对现代硬件是否重要)。

第三,大表通常是所有看起来与核心实体相关的数据的垃圾场;这很快使设计不清楚。例如,您展示的设计显示了 3 个不同的“状态”类型字段(状态、is_admin 和 fb_account_verified) - 我怀疑有一些业务逻辑应该将它们链接在一起(例如,管理员必须是经过验证的用户),但是您的设计不支持这一点。

这可能是也可能不是问题 - 它更多的是一个概念、架构/设计问题,而不是性能/它是否有效。但是,在这种情况下,您可以考虑创建表来反映有关帐户的相关信息,即使它没有 x 对多关系。因此,您可以创建“user_profile”、“user_credentials”、“user_fb”、“user_activity”,所有这些都由 user_id 链接。 这使它更整洁,如果您必须添加更多与 facebook 相关的字段,它们就不会悬在表格的末尾。但是,它不会使您的数据库更快或更可扩展。连接的成本可能可以忽略不计。

无论您做什么,选项 2 - 将“很少使用的字段”序列化为单个文本字段 - 都是一个糟糕的主意。您无法验证数据(因此日期可能无效,数字可能是文本,可能缺少非空值),并且在“where”子句中的任何使用都会变得非常缓慢。

一种流行的替代方法是“实体/属性/值”或“键/值”存储。此解决方案有一些好处 - 即使您的架构更改或在设计时未知,您也可以将数据存储在关系数据库中。但是,它们也有缺点:很难在数据库级别验证数据(数据类型和可空性),很难使用外键关系与其他表建立有意义的链接,查询数据可能变得非常复杂 - 想象一下找到所有status为1且facebook_id为null且注册日期大于昨天的记录。

鉴于您似乎知道数据架构,我会说“键/值”不是一个好的选择。

【讨论】:

  • 键值对表你怎么看。例如:user_info 具有以下字段(id,key,value)键值将是字段名称,值是列的值..这样,它可以轻松地将所有字段新或旧字段..
  • 我已经更新了答案 - 如果您知道数据的架构,并且它不是易失性的,那么键/值对于大多数关系需求来说并不是一个出色的解决方案。
  • 我已经创建了您的建议并添加到上述问题中,请检查,我也更详细地写了问题。
  • 我会说你的第二个 ERD 中的 2 个额外的表是有道理的;您可以将“名称”放在配置文件表中,但除此之外,我认为这一切都很清楚。
  • 我可能会说将多个字段序列化为一个文本字段通常是错误的解决方案。但是,这不一定是一个“可怕”的想法。在这种情况下,它可能是。但是,在其他情况下,如果这些字段是高度可变的和/或永远不会成为索引或加入的候选者,则有合理的理由。即会话状态、表单状态、具有动态字段名称或标签的对象、具有数百个属性的大型对象等。
【解决方案2】:

我建议进行一些测试。尝试两种方式并对其进行基准测试。没有人能够给你一个明确的答案,因为你没有分享你的硬件配置、示例数据、示例查询、你计划如何使用这些数据等。这里有一些你可能想要考虑的信息。

按预期使用数据库

关系数据库是专门为处理数据而设计的。就这样使用它。如果编写正确,在编写良好的模式中连接数据将表现良好。您可以使用 EXPLAIN 来优化查询。您可以记录慢速查询并提高其性能。数据库已经存在很多年了,如果将所有内容放在一个表中可以提高性能,您不认为这将成为互联网上的所有热门话题并且每个人都会这样做吗?

引擎类型

随着行数的增加,插入会受到怎样的影响?您使用的是 MyISAM 还是 InnoDB?您很可能希望使用 InnoDB,以便获得行级锁定而不是表。确保为您的表使用正确的引擎类型。获取您需要了解两者优缺点的信息。错误的引擎类型会影响性能。

使用分区提高性能

寻找提高性能的方法。例如,随着数据集的增长,您可以对数据进行分区。 Data partitioning 将通过将数据切片保存在单独的分区中来提高大型数据集的性能,从而允许您对大型数据集的部分而不是所有信息运行查询。

使用正确的列类型

考虑使用 UUID 主键来实现可移植性和未来增长。如果您使用正确的列类型,它将提高数据的性能。

不要序列化数据

使用序列化数据是更糟糕的方法。当您使用序列化字段时,您基本上是将数据库用作文件管理系统。它将保存和检索“文件”,但随后您的代码将负责反序列化、搜索、排序等。我只是花了一年时间试图解开这样的混乱。这不是数据库的用途。任何建议你这样做的人不仅给你不好的建议,而且他们不知道自己在做什么。在数据库中使用序列化数据的情况很少。

结论

最终,您必须做出最终决定。只需确保您充分了解并了解如何存储数据的利弊。我要给出的最后一条建议是找出 mysql 的重度用户在做什么。你认为他们将数据存储在一个表中吗?或者他们是否构建了一个关系模型并按照设计使用的方式使用它?

当你说“我要把所有东西都放在一个表中”时,你是在说你比那些不断致力于 MySQL 的开发人员团队更了解性能,并且可以在代码中做出更好的优化选择它是今天的样子。考虑将您的知识与 MySQL 团队以及每天使用它的 DBA、公司和数据库社区成员的累积知识进行权衡。

【讨论】:

  • 但是如果一张表需要 50+ 列怎么办,那怎么办?我们应该把它们分成不同的表吗?我正在检查 vb-forum,它有超过 70 列的用户表。
  • 定义需求。谁说它需要那样?一切都有原因/合理化。但要说它需要那样做,最终仍然是建筑和设计的选择。没有什么可以强迫他们将数据放在一个包含 70 多列的表中。
【解决方案3】:

在某些时候你应该看看“短排模型”,也称为实体键值存储,以及传统的“长排模型”。

如果您查看 WordPress 使用的架构,您会看到有一个包含 23 列的表 wp_posts 和一个包含 4 列(meta_id、post_id、meta_key、meta_value)的相关表 wp_post_meta。元表是一个“短行模型”表,它允许 WordPress 拥有无限的帖子属性集合。

“长排模型”或“短排模型”都不是最好的模型,通常最好的选择是两者的结合。正如@nevillek 指出的那样,搜索和验证“短行”并不容易,获取数据可能涉及旋转,这在 MySql 和 Oracle 中非常困难。

“长行模型”更容易验证、关联和获取,但当数据稀疏时,它可能非常不灵活且效率低下。某些行可能只有少数非空值。此外,您无法在不修改架构的情况下添加新列,这可能会导致系统中断,具体取决于您的架构。

我最近在一个金融服务系统上工作,该系统为每种工具提供了 700 多个可能的事实,大多数都少于 20 个事实。这可以通过设置几十个表来构建,每个表都针对特定的资产类别,或者作为一个包含 700 列的表,但我们选择使用一个包含大约 20 列(包含最流行的事实)的表和一个 4 列的组合包含其他事实的表格。这种设计效率很高,但访问起来很困难,因此我们在 PL/SQL 中构建了一些表函数来帮助解决这个问题。

【讨论】:

    【解决方案4】:

    我有一个一般性的评论,

    想一想:如果你把超过 10-12 列的东西放在一个表中,即使把它们放在一个表中是有意义的,我猜你会在短期、长期和中期付出代价术语。

    您的 3 表方法似乎比 1 表方法更好,但请考虑将它们制成 5-6 表而不是 3 表,因为您仍然可以。

    currentlycurrently_positioncurrently_linkuser-tableworkuser-profile 移动到一个新表中,主键名为USERWORKPROFILE

    将语言环境信息从 user-profile 移动到更新的 USERPROFILELOCALE 信息,因为它本质上是通用的。

    是的,所有表中的所有通用属性都应该是int 而不是varchar。 例如,City 需要移到一个名为 LIST_OF_CITIES 的新表和 cityid。 您的属性city 应该从varchar 更改为int 并指向LIST_OF_CITIES 中的cityid

    不用担心性能问题;您拥有的表越多,性能就越好,因为您实际上是将性能分配给数据库提供者,而不是全部掌握在自己手中。

    【讨论】:

    • 关于你拥有的表越多性能越好的评论是错误的,因为如果查询复杂性增加,你所拥有的连接会变慢。
    • 好的,我已经纠正了。我指的是关系上下文中的更多表,而不是独立的基础。例如,如果您在一张表中设置用户、城市,则性能将比在一张表中使用 user、city-id 和在另一张表中使用 city-id、city 并且它们之间具有引用完整性要慢。在后一种情况下,数据库服务器保存指向城市表的指针,而前一种情况则保存值。除此之外,数据库现在有 2 个索引可供使用。我写这篇评论纯粹是基于从数据库服务器的角度来看的优势。还有 3NF 收益。
    • 关于 10-12 列我之所以这么说是因为我觉得 10-12 列是您可以在浏览器页面上显示的创建/读取/更新/删除功能的理想列数或插入/更新/删除功能,具体取决于您如何使用它。如果你在一个表中放置 40 列左右,从浏览器/客户端的角度来看,你的页面视图的跨度会变得相当大。我不反对将所有相关数据放在一张表中,但我会尽我最大的努力让正在查看你的数据的用户在一个浏览器/客户端一瞥的完整视图,而无需滚动..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-21
    • 1970-01-01
    • 1970-01-01
    • 2018-12-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多