如何减少带有硬编码参数的SQL标量函数的执行时间?

如何减少带有硬编码参数的SQL标量函数的执行时间?,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我有一个现有的标量函数,它非常适合我。使用此函数执行基本查询在不到1秒的时间内完成。下面是函数的当前格式 BEGIN DECLARE @TEM VARCHAR(250); SET @TEM = ''; SELECT TOP 1 @TEM = ISNULL(B1_CHECKLIST_COMMENT,'') FROM BCHCKBOX WHERE B1_PER_ID1 =

我有一个现有的标量函数,它非常适合我。使用此函数执行基本查询在不到1秒的时间内完成。下面是函数的当前格式

BEGIN  
    DECLARE @TEM VARCHAR(250);  
    SET @TEM = '';  

    SELECT  
        TOP 1 @TEM = ISNULL(B1_CHECKLIST_COMMENT,'')     
    FROM  
        BCHCKBOX  
    WHERE  
        B1_PER_ID1 = @PID1 AND  
        B1_PER_ID2 = @PID2 AND  
        B1_PER_ID3 = @PID3 AND  
        REC_STATUS = 'A' AND  
        SERV_PROV_CODE = 'Code' AND  
        BCHCKBOX.B1_CHECKBOX_GROUP = 'APPLICATION' AND  
        UPPER(B1_CHECKBOX_DESC) LIKE UPPER(@info_label) ;  

    RETURN(@TEM);  
END 
MyFunction(‘Label’)
参数@PID1,2,3在我的查询中始终是相同的值,并且从不更改。因此,每当我在查询中使用该函数时,它的格式总是如下所示

MyFunction(ID1,ID2,ID3,’Label’)
由于前三个参数的值始终为ID1,2,3,我想将它们硬编码到函数中,我只需要为函数键入以下内容

BEGIN  
    DECLARE @TEM VARCHAR(250);  
    SET @TEM = '';  

    SELECT  
        TOP 1 @TEM = ISNULL(B1_CHECKLIST_COMMENT,'')     
    FROM  
        BCHCKBOX  
    WHERE  
        B1_PER_ID1 = @PID1 AND  
        B1_PER_ID2 = @PID2 AND  
        B1_PER_ID3 = @PID3 AND  
        REC_STATUS = 'A' AND  
        SERV_PROV_CODE = 'Code' AND  
        BCHCKBOX.B1_CHECKBOX_GROUP = 'APPLICATION' AND  
        UPPER(B1_CHECKBOX_DESC) LIKE UPPER(@info_label) ;  

    RETURN(@TEM);  
END 
MyFunction(‘Label’)
我尝试这样做的方式是将函数更改为以下内容

BEGIN  
    DECLARE @TEM VARCHAR(250);  
    SET @TEM = '';  

    SELECT  
        TOP 1 @TEM = ISNULL(B1_CHECKLIST_COMMENT,'')      
    FROM  
        BCHCKBOX X  
    WHERE  
        X.B1_PER_ID1 = ID1 AND  
        X.B1_PER_ID2 = ID2 AND  
        X.B1_PER_ID3 = ID3 AND  
        X.REC_STATUS = 'A' AND  
        X.SERV_PROV_CODE = 'Code' AND  
        X.B1_CHECKBOX_GROUP = 'APPLICATION' AND  
        UPPER(B1_CHECKBOX_DESC) LIKE UPPER(@info_label) ;  

    RETURN(@TEM);  
END  
在修订后的函数中,我给表格添加了别名,然后只使用实际值(ID1,2,3)而不是参数。该函数的工作原理与以前一样。但是,对于不到1秒的完全相同的查询,执行时间已增加到大约2分钟

为什么硬编码这些值会大大增加执行时间?是否有更好的方法格式化此函数,以实现与原始函数相同的执行时间

提前谢谢! 根据@AXIMIM和@SeanLange推荐的内容完成编辑后,原稿编辑如下,以说明该功能

ALTER  FUNCTION  [dbo].[FN_GetASIValue](@info_label  VARCHAR(250)) RETURNS VARCHAR (500)  AS    
    BEGIN 
        DECLARE
            @TEM VARCHAR(250),
            @ID1 VARCHAR(20),
            @ID2 VARCHAR(20),
            @ID3 VARCHAR(20);

        SELECT
            @TEM = '',
            @ID1 = 'B1_PER_ID1',
            @ID2 = 'B1_PER_ID2',
            @ID3 = 'B1_PER_ID3'

        SELECT
            TOP 1 @TEM = ISNULL(B1_CHECKLIST_COMMENT,'')

        FROM
            BCHCKBOX
        WHERE
            B1_PER_ID1 = @ID1 AND
            B1_PER_ID2 = @ID2 AND
            B1_PER_ID3 = @ID3 AND
            REC_STATUS = 'A' AND
            SERV_PROV_CODE = 'Code' AND
            B1_CHECKBOX_GROUP = 'APPLICATION'
        ORDER BY  B1_CHECKBOX_IND;
        RETURN(@TEM);
    END 
使用以下调用执行此函数不到一秒钟,返回的行数与原始函数相同

FN_GetASIValue('location')

但是,结果中“位置”列的值为空。原始函数确实在位置列中返回了文本。

我没有足够的声誉来评论您的问题,所以这里是您应该看的内容

有两个原因可能导致新版本速度缓慢

1) 硬编码值的类型不同于表BCHCKBOX中的类型,SQL对所有记录执行隐式转换。这种转换会妨碍索引的正确使用,并且会产生额外的开销

2) 查询不再使用以前的执行计划,因为没有更多的参数。需要创建新的执行计划

作为“修复”问题的建议,您可以简单地将硬编码值声明为函数体中的变量。这样,您就避免了这些问题,并且仍然可以获得只有一个参数函数的好处

BEGIN  
    DECLARE @TEM VARCHAR(250);  
    SET @TEM = '';  

    SELECT  
        TOP 1 @TEM = ISNULL(B1_CHECKLIST_COMMENT,'')     
    FROM  
        BCHCKBOX  
    WHERE  
        B1_PER_ID1 = @PID1 AND  
        B1_PER_ID2 = @PID2 AND  
        B1_PER_ID3 = @PID3 AND  
        REC_STATUS = 'A' AND  
        SERV_PROV_CODE = 'Code' AND  
        BCHCKBOX.B1_CHECKBOX_GROUP = 'APPLICATION' AND  
        UPPER(B1_CHECKBOX_DESC) LIKE UPPER(@info_label) ;  

    RETURN(@TEM);  
END 
MyFunction(‘Label’)
这就是我的意思。(假设类型为VARCHAR(50)。请使用与参数中相同的类型)


另外,你应该看看肖恩·兰格的评论。他指出了函数中应该考虑的一些其他问题。

ID1(例如)是文本值吗?如果是这样的话,它周围应该有单引号:
X.B1\u PER\u ID1='ID1',
ID1是一个文本值。最初修改查询时,我使用了“ID1”、“ID2”、“ID3”。在我看来,这是有道理的,因为它是文本。但是,查询没有返回任何记录。只有在我不使用引号的情况下,查询才会工作。一秒钟内返回的查询是否会产生与耗时2分钟的查询相同的行数?我不明白
ID1
ID2
ID3
如何可以是有效的文本。
BCHCKBOX
中是否有同名字段?因为这就是查询解析器应该认为的:字段名。什么样的数据类型是
@PID1
@PID2
@PID3
?此函数也存在一些明显的问题。您使用的是top 1,但没有订购人。您正在使用LIKE,它的行为类似于一个=。在最后一个谓词中有函数要计算UPPER,除非排序规则区分大小写,否则这是毫无意义的。谢谢大家的建议。我根据肖恩·兰格的建议进行了编辑。通过编辑,我在函数中声明了硬编码的值。不幸的是,这导致在执行查询时出现空白值。我将看看是否有一种方法可以对编辑后的代码进行评论以供审阅。尝试一次只做一次修改。通过这种方式,我们将知道函数是否因为处理Sean提出的问题而进行的调整或函数中声明变量的使用而中断。