如何减少带有硬编码参数的SQL标量函数的执行时间?
我有一个现有的标量函数,它非常适合我。使用此函数执行基本查询在不到1秒的时间内完成。下面是函数的当前格式如何减少带有硬编码参数的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 =
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提出的问题而进行的调整或函数中声明变量的使用而中断。