MySQL:长表vs宽表

时间:2013-04-15 23:19:28

标签: mysql database-design

什么是更高效(在查询性能方面)数据库表设计 - 长还是宽?

即,这个

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

第二个写入时间稍长(就多列而言),但两者的性能如何呢?如果可能,每种表格格式的一般优点/缺点是什么?

3 个答案:

答案 0 :(得分:6)

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

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

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

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

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

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


1 但是你应该确实衡量代表性的数据量。

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

答案 1 :(得分:2)

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

然而,正如Deltalima所说,第一种选择更灵活。不仅在涉及不同的查询选项时,而且当您/有一天需要使用其他尺寸,颜色等扩展表时。

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

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

答案 2 :(得分:1)

长期使用更灵活。它允许您过滤size例如

SELECT MAX(price) where size='L' 

它还允许在sizeid上建立索引。这会加快GROUP BY以及id和/或size此类产品库存表中其他表格加入的任何查询。