TSQL函数如何实现类似Python的memoization结果缓存功能?
TSQL 类 Python memoization 无侵入函数缓存实现方案
TSQL 无原生装饰器语法,无法完全实现 Python 那种无需修改任何代码即可为函数添加缓存的能力,但可通过以下两种简化路径实现需求,全程无需修改原函数的业务逻辑:
方案1:持久化缓存封装(最通用)
该方案适合跨会话、高频重复调用的场景,上层调用代码零修改:
- 第一步:创建缓存存储表,结构和原函数的入参、返回值完全匹配,为入参字段加联合唯一索引加速查询。
示例(原函数为dbo.HeavyCalc(@a int, @b varchar(50)) returns decimal(18,2)):CREATE TABLE dbo.FuncCache_HeavyCalc ( a INT, b VARCHAR(50), Result DECIMAL(18,2), ExpireTime DATETIME DEFAULT DATEADD(DAY,7,GETDATE()), -- 可选,控制缓存过期 CONSTRAINT PK_FuncCache_HeavyCalc PRIMARY KEY CLUSTERED (a, b) ) - 第二步:重命名原函数,用原函数名创建封装函数,实现缓存命中判断逻辑:
-- 重命名原函数 EXEC sp_rename 'dbo.HeavyCalc', 'HeavyCalc_Original'; GO -- 创建带缓存的封装函数,名称和原函数完全一致 CREATE OR ALTER FUNCTION dbo.HeavyCalc(@a INT, @b VARCHAR(50)) RETURNS DECIMAL(18,2) AS BEGIN DECLARE @Result DECIMAL(18,2) -- 优先查询未过期的缓存 SELECT @Result = Result FROM dbo.FuncCache_HeavyCalc WHERE a = @a AND b = @b AND ExpireTime > GETDATE() IF @Result IS NOT NULL RETURN @Result -- 缓存未命中调用原函数计算 SELECT @Result = dbo.HeavyCalc_Original(@a, @b) -- 结果写入缓存 INSERT INTO dbo.FuncCache_HeavyCalc(a,b,Result) VALUES (@a, @b, @Result) RETURN @Result END GO - 注意:可搭配SQL Server代理作业定期清理过期缓存,避免表体积过大。
方案2:会话级临时缓存
该方案适合单会话内多次重复调用相同参数的场景,无需维护持久化存储,会话结束缓存自动清除:
EXEC sp_rename 'dbo.HeavyCalc', 'HeavyCalc_Original'; GO CREATE OR ALTER FUNCTION dbo.HeavyCalc(@a INT, @b VARCHAR(50)) RETURNS DECIMAL(18,2) AS BEGIN DECLARE @Result DECIMAL(18,2) -- 会话缓存不存在则创建 IF OBJECT_ID('tempdb..#FuncCache_HeavyCalc') IS NULL CREATE TABLE #FuncCache_HeavyCalc ( a INT, b VARCHAR(50), Result DECIMAL(18,2), PRIMARY KEY CLUSTERED (a,b) ) -- 查缓存 SELECT @Result = Result FROM #FuncCache_HeavyCalc WHERE a = @a AND b = @b IF @Result IS NOT NULL RETURN @Result -- 计算并写入缓存 SELECT @Result = dbo.HeavyCalc_Original(@a, @b) INSERT INTO #FuncCache_HeavyCalc(a,b,Result) VALUES (@a,@b,@Result) RETURN @Result END GO
以上两种方案均仅需要对原函数做重命名操作,无需修改任何业务代码,上层调用感知不到任何变化,是目前TSQL环境下最接近Python memoization能力的实现。
内容的提问来源于stack exchange,提问作者Krzysztof Krysztofczyk
相关产品推荐
相关产品推荐

