我有一个用户定义的存储过程当调用而不传递显式值时,我只想传递所有位置 (nvarchar(50)),这是表的主键字段:Monitor_Locations(约 850 个条目)
SP 的一部分定义如下(截取)。
ALTER PROCEDURE [dbo].[dev_Tech@Locs2b] ( --CREATE or ALTER
@Locations as nvarchar(MAX) = NULL -- = 'GG1,BenBr14,BenBr00,YB_ToeDrain_Base'
,@rangeStart as DateTime = '1970-01-01'
,@rangeEnd as DateTime = '2099-12-31'
) AS BEGIN
SET NOCOUNT ON; --otherwise concrete5 chokes for multi-table returns.
DECLARE @loclist as TABLE (
Location nvarchar(50) PRIMARY KEY
)
IF @Locations is NULL
INSERT INTO @loclist(Location)
SELECT Location from Monitor_Locations order by Location
ELSE --irrelevant for this question
INSERT INTO @loclist(Location)
SELECT
ML.Location
FROM Monitor_Locations as ML join
tvf_splitstring(@Locations) as ss ON
ML.Location=ss.Item OR
ML.Location like ss.Item+'[_]%'
ORDER BY ML.Location;
With Deploys as (
SELECT
D.Location,
MIN(D.Start) as Start,
MAX(D.[Stop]) as Stop
FROM
Deployments as D
WHERE
D.Stop is not NULL
)
...做一些其他的事情...
为了在将受限站点列表发送到 SP 时提高存储过程的速度,我想将 WHERE 子句替换为
WHERE
CASE
WHEN D.Stop IS NULL THEN 0
WHEN @Locations IS NULL THEN 1 -- full list, so binding to another list doesn't do us any good.
WHEN EXISTS (SELECT 1 from (SELECT Location from @loclist as l where l.Location=D.Location) as ll) THEN 1 --ELSE NULL which is not 1
END=1
但是 SP 曾经需要 6-8 秒来执行,现在需要 2.5 分钟(对于没有限制列表的调用)。我认为完整列表的每种方式花费的时间大致相同,因为 CASE 的第二个子句应该很快被触发,而第三个子句永远不会被检查。
发生什么了?这段代码:
WHERE
CASE
WHEN D.Stop IS NULL THEN NULL
WHEN @Locations IS NULL THEN 1 -- full list, so binding to another list doesn't do us any good.
WHEN EXISTS (SELECT 1 from (SELECT Location from @loclist as l where l.Location=D.Location) as ll) THEN 1 --else null
END is not null
这个计划需要大约 10 分钟的运行时间:
对比这里的WHERE D.Stop is not NULL
计划(6s):
有一次,这个 SP 在这个版本中花费了 1 秒,但是通过更改 SP 然后再变回去,又花了 6 秒。如答案中所述,这可能是由于参数嗅探。
运行时间
我的目标执行时间少于 2 秒,因为这将是 Web 应用程序上频繁执行的 SP,它使用它来填充和限制其他用户选择。基本上,我不希望这是一个明显的瓶颈。初始运行时间大约为 3 分钟,但在添加或更改一些索引后,该时间下降到 6-8 秒范围。
星期一 (2016-08-29),在进行重大更改之前 没有输入参数的简单 WHERE:5 秒带有 rangeStart 和 rangeEnd 的简单 WHERE:4 秒带有 @Locations 设置为 7 元素 CSV 变量的简单 WHERE CASEd WHERE:最多 10 分钟
重新处理 CLR 函数后(见下面我的回答)星期二(2016 年 8 月 30 日)没有输入参数的简单或 CASEd WHERE 或带有 rangeStart 和 rangeEnd 的简单或 CASEd WHERE:3s 简单或 CASEd WHERE 有 7 个元素 @Locations:0 -1s
将表变量@loclist 迁移到临时表#loclist 后所有测试的 WHEREs/参数:0-1s