TSQL SVF 调用中的障碍

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 慢得多。

  1. 为什么 SQL Server 运行内联 SVF 查询的速度较慢 - 无论是在 CPU 还是运行时间方面?
  2. 通过集中一些简单的逻辑,我似乎通过代码重用阻碍了性能。我的问题是我需要在很多地方调用这个 SVF 而不复制逻辑。如果 SQL Server 在使用 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)