查询取决于计算值的高读取 table 的最佳方法

Best approach for high-read table where query depends on computed values

我有以下 table:

        StartDate - datetimeoffset(0);
    EventDuration - time(0);
RecurrenceEndDate - datetimeoffset(0);

关于此 table 的 99% 查询将需要计算 RecurrenceEndDate + EventDuration

此特定查询 select 仅与特定分析相关的记录 运行 非常非常频繁:

SELECT * FROM RRules WHERE

**RecurrenceEndDate + EventDuration** >= START_DATE --Make sure last recurrent event did/will not end before START_DATE, which would make the rule irrelevant for the analysis.

AND StartDate < END_DATE' --Make sure the first occurrence of the event is before END_DATE;

处理几乎每个查询都需要相同计算的这种情况的最佳方法是什么?我觉得将计算值存储在列上是错误的,因为它可以计算。

我建议你创建一个 computed column:

A computed column is a virtual column that is not physically stored in the table, unless the column is marked PERSISTED. A computed column expression can use data from other columns to calculate a value for the column to which it belongs.

例如,这将创建列 non-persisted,这意味着每次使用该列时都会进行计算:

ALTER TABLE MyTable ADD ChooseABetterName AS (RecurrenceEndDate + EventDuration)

或者作为与数据一起存储且不必每次都计算的持久列:

ALTER TABLE MyTable ADD ChooseABetterName AS (RecurrenceEndDate + EventDuration) PERSISTED

现在可以直接使用计算列了:

SELECT * FROM MyTable WHERE ChooseABetterName >= START_DATE

也可以create indexes on computed columns

but won't this still peform the computation every time?

是的,会的。 @DavidG 提供 。是的,您可以保留一个计算列,但是这会带来更好的性能还远非显而易见。

在数据库中,性能来自最小化 I/O。 I/O 成本是计算成本的数千倍。几乎任何用计算替换 I/O 的操作都是成功的。

例如,当计算机还很年轻,野生贵宾犬在地球上漫游时,我们在数据库中保存了随机数列表,以便更好地产生可重现的随机结果。后来,我们用生成它们的算法替换了这些表,因为一遍又一遍 re-compute 相同的数字比从磁盘上读取它们更快。

计算列为您节省了计算永远不会被读取的数字的成本、写入它们的时间以及维护该逻辑的时间。

最后,请记住:计算机科学中只有两件难事:缓存一致性和命名事物。您的 pre-computed 值是一个缓存,并引入了确保它们与基础值一致的问题。不难?好的。但是,在您知道有必要之前,为什么还要费心呢?

在整个表达式上创建持久计算列:

alter table RRules 
add column IsRelevant as (cast(case when StartDate + EventDuration >= StartDate then 1 else 0 end as bit)) persisted

将此列用作其他相关索引的一部分,而不是单独使用(因为选择性低)。您甚至可以将它添加到过滤索引的 WHERE 子句中。