我有一个存储过程大约需要2分钟才能执行, 我已经使用了几个临时表和while循环,我无法找出提高存储过程速度的最佳方法。 我的存储过程如下
ALter procedure _sp_Get_PatentAssignment_Mail_Test
(
@CompName nvarchar(max)='Canadian Spirit,Connexus Corporation'
)
As
Begin
Set NOCOUNT ON
Create table #temp
(
ID int identity(1,1),
AssigneeName nvarchar(100)
)
Create Table #tmpMainResult
(
Title nvarchar(1000),
Pat_PubNum varchar(30),
AssigneeName nvarchar(100)
)
IF(@CompName is NOT NULL AND @CompName<>'')
BEGIN
INSERT INTO #temp
SELECT * FROM dbo.uf_Split(@CompName,',')
END
DECLARE @MaxRownum INT
SET @MaxRownum = (SELECT MAX(ID) FROM #temp)
DECLARE @Iter INT
SET @Iter = (SELECT MIN(ID) FROM #temp)
WHILE @Iter <= @MaxRownum
BEGIN
Declare @AssigneeName nvarchar(100)
Set @AssigneeName= (SELECT AssigneeName
FROM #temp
WHERE ID = @Iter)
print @AssigneeName
Insert into #tmpMainResult
Select p.Title,
Case when p.PatentNum is null Or p.PatentNum=''
then
p.PublicationNum
else
p.PatentNum
end as 'Pat_PubName',
pa.AssigneeName
from Patent p
inner join PatentProperty pp on p.PatentId=pp.PatentId
inner join PatentAssignee pa on pp.PatentAssignmentID=pa.PatentAssignmentID
WHERE pa.AssigneeName like '%' +@AssigneeName+ '%'
SET @Iter = @Iter + 1
END
Select * from #tmpMainResult
drop table #temp
drop table #tmpMainResult
End
请提供一些减少执行时间的建议。
上面使用的函数如下:
ALTER FUNCTION [dbo].[uf_Split](@String varchar(MAX), @Delimiter char(1))
returns @temptable TABLE (items varchar(MAX))
as
begin
declare @idx int
declare @slice varchar(8000)
select @idx = 1
if len(@String)<1 or @String is null return
while @idx!= 0
begin
set @idx = charindex(@Delimiter,@String)
if @idx!=0
set @slice = left(@String,@idx - 1)
else
set @slice = @String
if(len(@slice)>0)
insert into @temptable(Items) values(@slice)
set @String = right(@String,len(@String) - @idx)
if len(@String) = 0 break
end
返回 端;
答案 0 :(得分:2)
一些建议:
1)你可以避免临时表DROP
。在sp的执行结束时,表将自动删除。
2)在临时表上定义Primary Key
答案 1 :(得分:1)
由于我们无法访问您的执行计划,因此建议的里程可能会有所不同。
如果您使用的是分割功能,则使用WHILE
很容易出错。发布您的分割功能代码。交替使用Jeff Moden的DelimitedSplit8K
在临时表中包含拆分字符串后,您不需要WHILE
。
您正在做的事情基本上是带有过滤器cross join
的{{1}}。
将您的插入内容更改为此类内容。
pa.AssigneeName like '%' +@AssigneeName+ '%'
由于您使用 Insert into #tmpMainResult
Select p.Title,
Case when p.PatentNum is null Or p.PatentNum=''
then
p.PublicationNum
else
p.PatentNum
end as 'Pat_PubName',
pa.AssigneeName
from Patent p
inner join PatentProperty pp on p.PatentId=pp.PatentId
inner join PatentAssignee pa on pp.PatentAssignmentID=pa.PatentAssignmentID
CROSS JOIN #temp t
WHERE pa.AssigneeName like '%' + t.AssigneeName + '%'
进行过滤,'%' + t.AssigneeName + '%'
或AssigneeName
上的索引可能无效。
同时检查两个表上的AssigneeName
和PatentId
是否有适当的索引
修改
Jeff Moden的分裂功能PatentAssignmentID
[dbo].[DelimitedSplit8K]
答案 2 :(得分:0)
正如其他一些人所说的那样,建议将是广泛而多样的,没有针对不同参数值的执行计划或执行计划(即不同的工作量)。但是,除了其他人已经声明的有效推荐以及作为索引和通常的嫌疑人之外,还有两个直接的领域需要考虑。
首先,始终尝试使用基于集合的操作而不是迭代代码。这不足以强调。让SQL决定如何处理查询而不是用循环告诉它。这通常是性能的巨大提升。
其次,尝试将临时表的使用与表变量进行比较。不要陷入一个比另一个更好的陷阱。证明给我看。调整代码来测试它需要很少的时间。我发现这在SQL Server 2005到2008 R2中是有益的。
代替执行计划结果,我将分开查询并逐表执行,以查看可以进行哪些最大的改进。打开Profiler并开始观察持续时间,读取等。