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

时间:2017-02-08 01:28:11

标签: sql sql-server calculated-columns

我有下表:

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

此表中99%的查询都需要计算RecurrenceEndDate + EventDuration

此特定查询仅选择相关记录进行特定分析,这种查询将非常频繁地运行:

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;

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

3 个答案:

答案 0 :(得分:3)

我建议你创建一个computed column

  

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

答案 1 :(得分:0)

  

但这不会每次仍然影响计算吗?

是的,它会的。 @DavidG正在提供right answer。是的,你可以坚持计算列,但是很明显会导致更好的性能。

在数据库中,性能来自最小化I / O. I / O的成本是计算的数千倍。几乎任何用计算取代I / O的东西都是胜利。

例如,当计算机还很年轻且野生长卷毛狗在地球上漫游时,我们在数据库中保留了随机数列表,这样可以更好地生成可重现的随机结果。后来,我们用生成它们的算法替换了这些表,因为重复计算相同数字的速度比从磁盘上读取它们要快得多。

计算列可以节省计算永远不会被读取的数字的成本,编写它们的时间以及维护该逻辑的时间。

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

答案 2 :(得分:0)

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

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

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