查询取决于计算值的高读取 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
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 子句中。
我有以下 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
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 子句中。