由于似乎没有可以计算值和管理缓存的单个函数,因此这里有一个为现有样本数据集提供值的合理有效方法的示例。UDF 将提供缓存或计算的值,但更新缓存仍然是单独的。
set nocount on;
-- Create some sample data and a partial cache of calculated values.
create table Samples ( Id Int Identity, A Int, B Int, V Int Null );
insert into Samples ( A, B ) values
( 0, 0 ), ( 0, 1 ), ( 1, 0 ), ( 1, 1 ), ( 2, 0 ), ( 0, 2 ), ( 0, 1 ), ( 0, 1 );
create table Cache ( Id Int Identity, A Int, B Int, V Int );
insert into Cache ( A, B, V ) values
( 1, 1, 1 ), ( 0, 2, 4 );
go
-- Create the function to perform the expensive calculation.
create function dbo.ExpensiveCalculation( @A Int, @B Int )
returns Int
as
begin
return @A * @A + @B * @B;
end;
go
-- And another function that can use cached values.
create function dbo.ExpensiveCalculationWithCaching( @A Int, @B Int )
returns Int
as
begin
declare @Result as Int
-- Try to get a cached value.
select @Result = V
from Cache
where A = @A and B = @B;
-- If we didn't find a cached value then calculate one.
if @@RowCount = 0
select @Result = dbo.ExpensiveCalculation( @A, @B );
return @Result;
end;
go
-- Apply any previously cached values to the samples.
update S
set S.V = C.V
from Samples as S inner join
Cache as C on C.A = S.A and C.B = S.B;
print Cast( @@RowCount as VarChar(6) ) + ' samples satisfied from initial cache.'
declare @BatchSize as Int = 3; -- Number of rows to process with the function in each iteration.
declare @CacheIds as Table ( Id Int );
-- Update the samples one batch at a time.
while exists ( select 42 from Samples where V is NULL )
begin
-- Clear the intermediate data, if any.
delete from @CacheIds;
-- Find a batch of unknown values with distinct input values and apply the function.
-- Add the results to the cache and note the id's of the new rows.
insert into Cache
output inserted.Id into @CacheIds
select top (@BatchSize) A, B, dbo.ExpensiveCalculation( A, B )
from Samples
where V is NULL
group by A, B;
print Cast( @@RowCount as VarChar(6) ) + ' cache entries added.'
-- Update any samples that benefit from the newly cached values.
update S
set S.V = C.V
from Samples as S inner join
Cache as C on C.A = S.A and C.B = S.B inner join
@CacheIds as CI on CI.Id = C.Id
where S.V is NULL;
print Cast( @@RowCount as VarChar(6) ) + ' samples satisfied from cache update.'
end
-- Display the results.
select Id, A, B, V
from Samples
select dbo.ExpensiveCalculationWithCaching( 1, 1 ) as Cached,
dbo.ExpensiveCalculationWithCaching( 4, 4 ) as Calculated
-- Houseclean.
drop function dbo.ExpensiveCalculationWithCaching;
drop function dbo.ExpensiveCalculation;
drop table Samples;
drop table Cache;
注意:如果添加到Samples
表中的行在执行此代码期间被更新,则它们可能不会被处理。