在我们的代码中,我们必须在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。
答案 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)