MySQL 数据库结构:多列或多行

Posted

技术标签:

【中文标题】MySQL 数据库结构:多列或多行【英文标题】:MySQL database structure: more columns or more rows 【发布时间】:2012-10-20 11:59:18 【问题描述】:

我收集人们如何用表格中的类别标记主题,例如:

ID | topic_id | votes_Category_1 | votes_Category_2 |.......... | votes_Category_12

出于历史原因,我每小时转储一次此表。 假设表包含 200 万行。每小时在历史表中转储一次。

如果我想添加列Category_13,这个解决方案不灵活,所以我正在考虑这个:

ID | topic_id | Category_id | vote_count

此解决方案将为每个主题创建 12 行,其结构更好且更灵活,但我必须每小时转储 2400 万行。

我需要每个类别中最好的 10 个主题! 我想知道在案例 2 中使用 Max on votes(其中 category_id=x 和 topic_id=y)是否会比案例 1 慢: Order by categoy_x where topic_id=y

哪一个会更好!从性能的角度来看:

    拥有 200 万行 14 列 拥有 4 列 2400 万行

谢谢

【问题讨论】:

其实是切换到 NoSQL 数据库的一个很好的例子。 :-) 别忘了 option1 +按 votes_category_xxx 排序需要 XXX 索引。规范化版本(选项 2)将具有恒定数量的索引/键约束。 【参考方案1】:

我会查看检索模式来决定方法。

    如果您按类别检索主题,那么我将采用第二种方法,在类别字段上定义索引,以便给定类别的所有记录连续(相对)存储在磁盘上,从而导致要检索的磁盘页数较少。这也是因为与所有类别作为列的表相比,记录大小更小。优点是可以灵活地轻松添加更多类别,缺点是(ID,TopicID)列数据的重复会影响数据的总大小。

    如果您按主题检索,那么我将采用第一种方法,即在该主题上定义一个索引。这将减少每个类别的 (ID, TopicID) 列值的重复,从而减少要存储的数据的总大小,并且由于行数以每小时数百万为单位,这种大小的减少必须是显着的。缺点是需要修改新类别的架构。

编辑: 考虑您编辑的检索模式:

我检索每个类别的热门主题及其值,因此我在案例 1 中按 votes_Category_x 排序。

我理解为Find the top N topics with largest number of votes in a given category

在情况 2 中,我会寻找每个 topic_id 的 max(category)。

这是SELECT TopicID, MAX(votes) FROM TABLE GROUP BY TopicID, Category

200 万行和 2400 万行的记录大小不同,但是是的,ID 和 TopicID 重复,这肯定会增加数据大小,每条记录增加 8 个字节。

第一个表存储 200 万条大小为 60 bytes (4*15 ints) 的记录,第二个表存储了 2400 万条大小为 16 bytes (4*4 ints) 的记录。第二个表将每小时添加~624KB。在一段时间内似乎是一个问题。由于在中间插入数据,这也会影响碎片,因为在第二种方法的情况下,索引是按类别组织的。

在继续使用其中一种表结构之前,可能值得进行一些性能测试以更好地理解这一点并权衡添加类别的频率。

【讨论】:

~ntg,当您有 14 个字段记录与 3 个字段记录时,您正在打折性能下降的方式。 @ntg,尝试围绕表格结构做一些数学运算并更新了我的回复。 @ntg,我的错,我在第一种方法中将类别列计数为 varchars,尽管它们包含整数计数。感谢您指出。列在任何地方都是整数,每小时数据库页数的差异保持不变,这可能是一个问题。 @ntg,如果您在检索过程中对所有列不感兴趣,并且您可以使用垂直分区移出不存在的列,您可以节省记录大小,即列数对单独的表感兴趣以减少记录大小,从而减少整个表跨越的数据库页数。如果您的表结构中有许多 varchar 列,则这是相关的。但是在您的情况下,所有列都是整数类型,并且按类别将计数存储在单独的行中会对整个表的大小产生不利影响。因此,每行一个类别似乎很昂贵。 在情况 2 中可能会更慢,因为索引将在类别上定义,而在情况 1 中可能会更快,因为索引将在 topic_id 上定义。

以上是关于MySQL 数据库结构:多列或多行的主要内容,如果未能解决你的问题,请参考以下文章

MySQL关联表多行转多列?

php mysql批量或批量更新多列和多行但如果列不为空则不更新

mysql 多行(GROUP_CONCAT)和多列(CONCAT)的合并函数

Xamarin 表单:显示和绑定具有多行和多列的列表/网格的数据

MySQL基础

循环遍历具有多列和多行的数组