SQL Server 是否会缓存非持久化计算列的结果以便可以重复使用而不会产生重新计算的成本?
附加上下文 我一直建议如果使用计算列,你应该使用 PERSISTED 选项,除非你期望插入/更新频率高于读取频率,或者你需要比读取更好的插入/更新性能数据(即因为计算成本必须在其中一个或另一个上产生,所以决定实际上是你想支付该成本的地方)。
还考虑了计算数据的额外存储,但通常这可以忽略不计且便宜,因此无需过多考虑。
但是,我想检查我的建议是否完全准确,因为 SQL 可能更智能……即一旦 SQL 计算出一个计算列,它就可以将这个值记录在内存中,这样它就不必在后续的计算中重新计算该值查询。SQL 可以在缓存值上有一个时间戳,在基础记录数据上有另一个时间戳,以说明自计算值计算以来该记录是否已更改,以确定缓存值是否仍然有效。
是否有类似的东西/它是否取决于可用资源(例如内存)或其他因素(例如缓存值是否具有超出进程生命周期的 TTL)?我从来没有读过任何暗示这存在的东西,但如果没有在幕后进行一些优化,我会感到惊讶。
非持久计算列值不会缓存在内存中。
这是一个简短的演示,证实了这一点。首先,我将为我们的测试创建一个数据库:
然后创建一个没有计算列的表作为基线。此表中的列大小是专门选择的,因此 4 行将正好填满一个 8KB 数据页(因此 SQL Server 的缓冲区缓存中的一页为 1):
接下来,我将创建同一个表,但添加了一个计算列:
接下来,我将确保将这 8 行写入磁盘,然后清除缓冲区缓存,然后选择所有 8 行以便将它们拉入内存:
最后,我将使用这个我完全没有从 Aaron Bertrand 那里窃取的查询*
从那里,您可以看到这两个表中的每一个在内存中只有一页。如果计算列存储在内存中,它会将第二个表的行推到第二页上。
您还可以在实际执行计划中看到每次发生的计算:
如果您确实需要为特定查询“缓存”非持久计算列,您实际上可以在它们上创建一个非聚集索引。这样它们就存储在索引中,而不是存储在基表中。
*请参阅确定数据库和对象使用的 SQL Server 内存,这是代码: