MySQL:长表vs宽表

sas*_*llo 7 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
Run Code Online (Sandbox Code Playgroud)

与此相比

id  S     M     L
1   12.4  23.1  33.3
2   3.3   5.3   11.0
Run Code Online (Sandbox Code Playgroud)

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

SELECT AVG(price) FROM table GROUP BY size
Run Code Online (Sandbox Code Playgroud)

要么

SELECT AVG(S), AVG(M), AVG(L) FROM table
Run Code Online (Sandbox Code Playgroud)

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

Bra*_*vic 6

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

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

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

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

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

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


1但是你应该真正衡量代表性的数据量.

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