use*_*139 6 performance sql-server t-sql query-performance
我有一个简单的 Products 数据表,其中包含 100k 条记录(仅生成一些随机数据):
set nocount on
create table dbo.temp_Products
(
[ProductID] int,
[Type] tinyint,
[Price] float,
[Weight] float
)
declare @rowcnt int = 0
while (@rowcnt <= 100000)
begin
insert into dbo.temp_Products
select @rowcnt, 1+rand()*4, 1+rand()*100, 1+rand()*10
set @rowcnt = @rowcnt + 1
end
Run Code Online (Sandbox Code Playgroud)
以及进行简单逻辑计算的标量值函数:
create function dbo.usvf_CalculateShipping
(
@PricePerKG float = 1,
@Type tinyint,
@WeightInKG float = 1
)
returns float
as
begin
return /*get the appropriate factor to apply*/
case
when @Type = 1 then 0.1
when @Type = 2 then 0.2
when @Type = 3 then 0.35
when @Type = 4 then 0.43
end * @PricePerKG * @WeightInKG
end
Run Code Online (Sandbox Code Playgroud)
但是,当我运行查询来调用 SVF 时,相对于调用内联逻辑的查询,结果性能会受到影响。执行的SQL语句和结果如下:
查询语句:
select ProductID, case
when [Type] = 1 then 0.1
when [Type] = 2 then 0.2
when [Type] = 3 then 0.35
when [Type] = 4 then 0.43
end *Price*[Weight] from temp_Products
where [Weight] between 2 and 8
select ProductID, dbo.usvf_CalculateShipping(Price, [Type], [Weight]) from temp_Products
where [Weight] between 2 and 8
Run Code Online (Sandbox Code Playgroud)
结果:
Table 'temp_Products'. Scan count 1, logical reads 390, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 109 ms, elapsed time = 103 ms.
(59938 row(s) affected)
Table 'temp_Products'. Scan count 1, logical reads 390, physical reads 0, read- ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 609 ms, elapsed time = 629 ms.
Run Code Online (Sandbox Code Playgroud)
但是如果我得到同时运行两个查询的执行计划,每个查询的相对成本是 50%,即使内联 SVF 慢得多。
Mik*_*son 10
为什么 SQL Server 运行内联 SVF 查询的速度较慢 - 无论是在 CPU 还是运行时间方面?
标量值函数在与主查询不同的上下文中执行,并且为每个调用设置它需要时间。
通过集中一些简单的逻辑,我似乎通过代码重用阻碍了性能。
是的,对于标量值函数,这是真的。
如果 SQL 服务器在使用 SVF 时总是妨碍性能,我为什么要使用它们
好问题,不确定我是否可以提供一个用例,其中标量值函数将是显而易见的答案。
有不同的解决方案吗?
是的,您可以改用内联表值函数。
create function dbo.usvf_CalculateShipping2
(
@PricePerKG float = 1,
@Type tinyint,
@WeightInKG float = 1
)
returns table as return
select case
when @Type = 1 then 0.1
when @Type = 2 then 0.2
when @Type = 3 then 0.35
when @Type = 4 then 0.43
end * @PricePerKG * @WeightInKG as Shipping
Run Code Online (Sandbox Code Playgroud)
您还必须更改调用函数的方式。
select ProductID,
(
select Shipping
from dbo.usvf_CalculateShipping2(Price, [Type], [Weight])
)
from temp_Products
where [Weight] between 2 and 8
Run Code Online (Sandbox Code Playgroud)