【问题标题】:MySQL: Long table vs wide tableMySQL:长表与宽表
【发布时间】:2016-06-26 15:13:24
【问题描述】:

哪种数据库表设计更有效(就查询性能而言)——长的还是宽的?

也就是说,这个

id size price
1  S    12.4  
1  M    23.1
1  L    33.3
2  S    3.3
2  M    5.3
2  L    11.0

与此相反

id  S     M     L
1   12.4  23.1  33.3
2   3.3   5.3   11.0

通常(我认为)归结为GROUP BY 和直接选择列之间的性能比较:

SELECT AVG(price) FROM table GROUP BY size

SELECT AVG(S), AVG(M), AVG(L) FROM table

第二个写的有点长(就很多列而言),但是两个的性能呢?如果可能,这些表格格式的一般优点/缺点是什么?

【问题讨论】:

    标签: mysql database-design


    【解决方案1】:

    首先,这是两种不同的数据模型,适用于不同的目的。

    话虽如此,我希望1第二种模型的聚合速度更快,因为数据打包得更紧凑,因此需要更少的 I/O:

    • 第一个模型中的 GROUP BY 可以通过对索引 {size, price}完整扫描来满足。当数据太大而无法放入 RAM 时,索引的替代方法会太慢。
    • 第二个模型中的查询可以通过全表扫描来满足。不需要索引2

    由于第一种方法需要表 + 索引,而第二种方法只是表,因此在第二种情况下缓存利用率更好。即使我们忽略缓存并将第一个模型中的索引(无表)与第二个模型中的表进行比较,我怀疑索引会比表大,仅仅是因为它物理记录了size并且有未使用的“孔” " 对于 B 树来说是典型的(尽管如果表是 clustered 也是如此)。

    最后,第二个模型没有索引维护开销,这可能会影响 INSERT/UPDATE/DELETE 性能。

    除此之外,您可以考虑将 SUM 和 COUNT 缓存在仅包含一行的单独表中。每当在主表中插入、更新或删除行时,都会通过触发器更新 SUM 和 COUNT。然后,您可以轻松获得当前的 AVG,只需将 SUM 和 COUNT 相除。


    1 但是您确实应该衡量具有代表性的数据量以确保确定。

    2 由于您的查询中没有 WHERE 子句,因此将扫描所有行。索引仅用于获取表行的相对较小的子集(有时用于index-only scans)。作为粗略的经验法则,如果需要表中超过 10% 的行,索引将无济于事,即使索引可用,DBMS 通常也会选择全表扫描。

    【讨论】:

    • 非常感谢您的精彩解释!最后你的额外 cmets 非常有用,我的问题只是对我面临的一个更大问题的简要总结,我一定会仔细考虑这些。
    【解决方案2】:

    第一个选项会产生更多行,并且通常会比第二个选项慢。

    但是,正如 Deltalima 还指出的那样,第一个选项更灵活。不仅涉及到不同的查询选项,而且当你有一天需要用其他大小、颜色等扩展表格时。

    除非您有一个非常大的数据集或需要超快速的查找时间,否则您可能会更好地选择第一个选项。

    如果您确实拥有或需要非常大的数据集,则最好创建一个包含预先计算的汇总值的表格。

    【讨论】:

      【解决方案3】:

      long 使用起来更灵活。例如,它允许您过滤size

      SELECT MAX(price) where size='L' 
      

      它还允许在sizeid 上建立索引。这加快了GROUP BY 和其他表在id 和/或size 这样的产品库存表上连接的任何查询。

      【讨论】:

      • 选择最大(L)?
      猜你喜欢
      • 2011-12-19
      • 2017-10-07
      • 2021-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-03
      • 2020-11-20
      • 2016-04-11
      相关资源
      最近更新 更多