具有复杂WHERE条件的高效SELECT - 我是否需要存储具有计算值的列?

时间:2012-10-08 02:05:11

标签: sql django database-design normalization django-orm

假设我有一个大表来存储整数范围。我可以用两个字段做到这一点:

start|end
  10 |210     (represents 10 to 210)
  5  |55      (represents 5 to 55)

(快速选择end列)或:

start|length
  10 | 200     (represents 10 to 210)
  5  | 50      (represents 5 to 55)

(快速选择length列)。

如果我有时需要end选择,有时候选择length,并且两个查询都需要快速查看,该怎么办?我可以存储两个:

start|length|end
  10 | 200  |210
  5  | 50   |55

但是这不是规范化的,每个人都必须记住更新这两个字段,而且只是糟糕的设计。

我知道我可以选择start + lengthend - start,但对于一张非常大的桌子,这不是非常慢吗?

如何在不存储冗余数据的情况下快速查询计算值 - 或者我应该只存储额外的列?

3 个答案:

答案 0 :(得分:2)

根据您使用的数据库类型,您可能希望使用触发器来计算派生字段。这样,他们永远不会失去同步。

这意味着每次开始或结束更改时都可以重新计算字段(长度)。

答案 1 :(得分:1)

我会存储长度,但我确保计算是在插入和更新sprocs中完成的,这样只要每个人都使用你的sprocs,就不会有更多的开销。

答案 2 :(得分:1)

不幸的是,您的目标数据库都不支持计算列。我会做以下事情:

  1. 首先,确定您是否确实遇到了性能问题。确实WHERE end - start = ?的执行速度比WHERE length = ?慢,但是您没有定义应用程序中“真正的大表”是什么,也不是所需的性能。无需优化可能不存在的问题。
  2. 确定您是否可以支持搜索中的任何延迟。如果是这样,您可以将计算列添加到表中,但专门执行一个单独的任务,每五分钟,每小时或其他任何一个,以填充值。
  3. 在PostgreSQL中你可以考虑一个物化视图,我相信在引擎级别支持 。 (参见Catcall的评论,见下文)。
  4. 最后,如果所有其他方法都失败了,请考虑使用触发器来维护计算列。