查询依赖于计算值的高读取表的最佳方法



我有下表:

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

该表上99%的查询将需要计算CCD_ 1。

这个只为特定分析选择相关记录的特定查询将非常非常频繁地运行:

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;

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

我建议您创建一个计算列:

计算列是不物理存储在表中的虚拟列,除非该列标记为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

也可以在计算列上创建索引。

但这不是每次都会影响计算吗?

是的,会的。@DavidG提供了正确的答案。是的,您可以持久化一个计算列,但这并不能带来更好的性能。

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

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

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

最后,请记住:计算机科学中只有两件困难的事情:缓存一致性和命名。预先计算的值是一个缓存,并引入了确保它们与基础值一致的问题。不难吗?好吧。但在你知道有必要之前,为什么还要麻烦呢?

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

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

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

最新更新