如果标量作为CASE包装器运行,则标量函数会运行

时间:2016-07-19 07:43:03

标签: sql-server sql-server-2012 sql-server-2014

在我们的代码中,我们必须在SELECT语句中带回一些连接的字符串,我们必须使用CASE语句。事情是,我们必须做几个地方,如果你需要改变一些东西,你必须在多个地方做,这是非常烦人的。

这看起来非常像:

SELECT P.ProductID
    , P.Name
    , CASE P.Flag
        WHEN 1 THEN 'Case 1'
        WHEN 2 THEN 'Case 2'
        WHEN 3 THEN CONCAT('Case 3', P.SomeProductColumn)
    END AS Something
FROM dbo.Product AS P;

当然,这过于简单了,但你得到了图片。现在我想创建一个可以作为包装器的标量函数。像这样:

CREATE FUNCTION dbo.MyFunction
(
    @Flag SMALLINT
    , @SomeProductColumn VARCHAR(100)
)
RETURNS VARCHAR(100) AS
BEGIN
    RETURN CASE @Flag
        WHEN 1 THEN 'Case 1'
        WHEN 2 THEN 'Case 2'
        WHEN 3 THEN CONCAT('Case 3', @SomeProductColumn)
    END
END

所以我现在可以这样执行我的查询:

SELECT P.ProductID
    , P.Name
    , dbo.MyFunction(P.Flag, P.SomeProductColumn) AS Something
FROM dbo.Product AS P;

它看起来不仅更干净,而且现在我已经封装了列计算逻辑,并且它将更容易管理它。

我已经阅读了很多内容,我应该避免在sql server中使用标量函数,因为它们是性能杀手,但是它们中的大多数(大多数)都包含函数,查询特定的表以及每行调用该函数,即1000行将调用该函数1000次,并且表也将被查询1000次。

接近,我正在寻找,以一种糟糕的方式影响查询性能?我不确定如何测试。如果已经回答了这个问题,请不要犹豫将其链接或将问题标记为dupe。

1 个答案:

答案 0 :(得分:1)

标量和多语句用户定义的函数都是出色的性能。尽管内联用户定义的函数看起来几乎相同,但它们不会产生相同的性能影响,通常是实现此类功能的最佳方式。

检查查询性能影响的最简单方法是从计划缓存sys.dm_exec_query_stats + sys.dm_exec_sql_text开始。注释部分用于显示查询计划:

select top 50
    SUBSTRING(t.text, (s.statement_start_offset/2)+1,
        ((CASE s.statement_end_offset
        WHEN -1 THEN DATALENGTH(t.text)
        ELSE s.statement_end_offset
        END - s.statement_start_offset)/2) + 1) as statement_text,
    t.text,
    s.total_logical_reads, 
    s.total_logical_reads / s.execution_count as avg_logical_reads,
    s.total_worker_time, 
    s.total_worker_time / s.execution_count as avg_worker_time,
    s.execution_count,
    --,cast(p.query_plan as xml) as query_plan
from 
    sys.dm_exec_query_stats s
    outer apply sys.dm_exec_sql_text (sql_handle) t
    --outer apply sys.dm_exec_text_query_plan (plan_handle, statement_start_offset, statement_end_offset) p
where 
    t.text like '%something to find your query%'
order by 
    total_logical_reads desc
option (recompile)