MySQL:长表与宽表

标签 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

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

最佳答案

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

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

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

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

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

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


1 但您确实应该测量有代表性的数据量才能确定。

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

关于MySQL:长表与宽表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16026226/

相关文章:

sql - 关系数据库中分面搜索的高效实现

MySQL限制一组记录

php - 数组到字符串转换 "Array"存储到数据库

php - 查询成功时链接到页面

php - 聪明的foreach循环

mysql - 另一个数据库设计难题

mysql - 如何挑选价格高或低20%的产品?

sql - 我应该使用 SQL_Variant 数据类型吗?

database-design - 为什么 ERD 中不允许使用特定的基数?

sql - Oracle 模式表名称限制