10

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

即,这

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

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

4

3 回答 3

9

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

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

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

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

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

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


1但您确实应该测量具有代表性的数据量,以确保这一点。

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

于 2013-04-16T12:08:58.397 回答
3

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

然而,正如 Deltalima 也指出的那样,第一种选择更灵活。不仅涉及不同的查询选项,而且如果/当您有一天需要用其他尺寸、颜色等扩展表格时。

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

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

于 2013-04-15T23:38:00.253 回答
2

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

SELECT MAX(price) where size='L' 

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

于 2013-04-15T23:26:41.433 回答