如何修复sql server 2005中的用户定义函数标量值性能问题?

时间:2010-12-01 17:00:41

标签: sql sql-server performance sql-server-2005 tsql

用户定义函数用于存储过程。用户定义函数返回标量值。遵循用户定义函数中使用的逻辑

CREATE  FUNCTION [dbo].[udf_Test] ( @Code varchar(10),  )  
  RETURNS bit AS    
BEGIN 
  DECLARE @bFlag bit  

  SELECT @bFlag = COUNT(id)  
    FROM tbL1  
   WHERE Code = @Code  

  IF  @bFlag = 0   
  BEGIN  
    SELECT @bFlag = COUNT(id)  
      FROM tbl2
     WHERE LTRIM(RTRIM(Code)) = @Code  
  END  

  IF @bFlag = 0   
  BEGIN  
    SELECT @bFlag = COUNT(id)  
      FROM tbl3  
     WHERE LTRIM(RTRIM(Code)) = @Code  
  END  

  IF @bFlag = 0   
  BEGIN  
    SELECT @bFlag = COUNT(id)  
      FROM tbl4
     WHERE LTRIM(RTRIM(Code)) = @Code  
  END

RETURN @bFlag 

这是提高上述用户定义函数性能的正确方法吗?

2 个答案:

答案 0 :(得分:8)

提高性能的最佳方法是完全抛弃UDF。

我发生的一件事就是

LTRIM(RTRIM(Code)) = @Code

不是sargable所以每次调用(即外部查询中返回的每一行)都可能导致最多4次表扫描。

如果在查询中使用内联的CASE表达式替换UDF中的逻辑,则可能会得到much superior execution plan。即使你不能使谓词至少变得可思考,它也会允许优化器探索不同的连接策略,例如散列连接,而不是强制重复扫描相同的表。

答案 1 :(得分:2)

现在......

WHERE LTRIM(RTRIM(Code)) = @Code;使用ltrim(rtrim(..将阻止索引被使用。

理想情况下,您应该将ltrim(rtrim(Code))的结果作为索引col,以便可以在WHERE子句中使用索引。这会加快速度。

@bFlag = COUNT(id)为int且@bFlag为int时设置COUNT(id)并不是那么好!你真的应该使用CASE WHEN COUNT(id) > 0 THEN 1 ELSE 0 END或其他。

但是,使用IF EXISTS的方法更有效,因为只要找到符合条件的单行,这种方法就会短路。

DECLARE @bFlag bit 
SELECT @bFlag = 0

IF EXISTS (SELECT 'x' FROM tbl1 where Code= @Code ) SELECT @bFlag = 1
-- etc.
RETURN @bFlag