如何提高存储过程的性能

时间:2015-06-04 10:28:51

标签: sql sql-server sql-server-2008 sql-server-2008-r2

我有一个存储过程大约需要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   

返回 端;

3 个答案:

答案 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上的索引可能无效。

同时检查两个表上的AssigneeNamePatentId是否有适当的索引

修改

Jeff Moden的分裂功能PatentAssignmentID

[dbo].[DelimitedSplit8K]

答案 2 :(得分:0)

正如其他一些人所说的那样,建议将是广泛而多样的,没有针对不同参数值的执行计划或执行计划(即不同的工作量)。但是,除了其他人已经声明的有效推荐以及作为索引和通常的嫌疑人之外,还有两个直接的领域需要考虑。

首先,始终尝试使用基于集合的操作而不是迭代代码。这不足以强调。让SQL决定如何处理查询而不是用循环告诉它。这通常是性能的巨大提升。

其次,尝试将临时表的使用与表变量进行比较。不要陷入一个比另一个更好的陷阱。证明给我看。调整代码来测试它需要很少的时间。我发现这在SQL Server 2005到2008 R2中是有益的。

代替执行计划结果,我将分开查询并逐表执行,以查看可以进行哪些最大的改进。打开Profiler并开始观察持续时间,读取等。