我有一个可以在可接受的时间内运行的查询,但我想从中获得最大的性能。
我要改进的操作是计划的右侧节点17处的“索引搜索”。
我已经添加了适当的索引,但是对于该操作,我得到的估计值是它们应有的一半。
我一直在寻找更改索引,添加临时表并重新编写查询的方法,但是为了获得正确的估算值,我无法对其进行简化。
有人对我可以尝试的方法有任何建议吗?
更新:
我觉得问题的最初版本引起了很多混乱,因此我将在原始代码中添加一些解释。
create procedure [dbo].[someProcedure] @asType int, @customAttrValIds idlist readonly
as
begin
set nocount on;
declare @dist_ca_id int;
select *
into #temp
from @customAttrValIds
where id is not null;
select @dist_ca_id = count(distinct CustomAttrID)
from CustomAttributeValues c
inner join #temp a on c.Id = a.id;
select a.Id
, a.AssortmentId
from Assortments a
inner join AssortmentCustomAttributeValues acav
on a.Id = acav.Assortment_Id
inner join CustomAttributeValues cav
on cav.Id = acav.CustomAttributeValue_Id
where a.AssortmentType = @asType
and acav.CustomAttributeValue_Id in (select id from #temp)
group by a.AssortmentId
, a.Id
having count(distinct cav.CustomAttrID) = @dist_ca_id
option(recompile);
end
答案:
为什么在pasteThePlan链接中使用奇怪的初始命名?
答:因为我使用了SQL Sentry Plan Explorer中的匿名计划。
为什么
OPTION RECOMPILE
呢答:因为我可以负担得起重新编译以避免参数嗅探的作用(数据可能是/可能是歪斜的)。我已经测试过,并且对Optimizer在使用时生成的计划感到满意
OPTION RECOMPILE
。WITH SCHEMABINDING
?答:我真的想避免这种情况,只有在拥有索引视图时才使用它。无论如何,这是一个系统函数(
COUNT()
),因此SCHEMABINDING
此处无用。
回答更多可能的问题:
我为什么用
INSERT INTO #temp FROM @customAttrributeValues
?答案:因为我注意到并且现在知道使用查询中插入的变量时,使用变量进行的任何估算始终为1。我测试了将数据放入临时表中,然后估算与实际行相等。
为什么要使用
and acav.CustomAttributeValue_Id in (select id from #temp)
?答:我可以用#temp上的JOIN替换它,但是开发人员非常困惑,因此
IN
选择了该选项。我真的认为即使更换也不会有任何区别,无论哪种方式,这都没有问题。
select id from @customAttrValIds
而不是时select id from #temp
,估算的行数是1
针对变量和3
#temp的(与实际的行数匹配)。这就是为什么我换成@
用#
。我确实记得有一次演讲(来自Brent O或Aaron Bertrand),他们说,当使用tbl变量时,该变量的估计值始终为1。并且为了获得更好的估计值,他们将使用临时表。
#temp
创建和使用将是性能的问题,而不是收益。您将保存到未索引表中,仅可使用一次。尝试将其完全删除(并可能将其更改in (select id from #temp)
为exists
子查询。