我有下表:
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;
处理这种情况的最佳方法是什么,几乎每个查询都需要相同的计算?我觉得在列上存储计算值是错误的,因为它可以被计算出来。
答案 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
答案 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子句中。