SQL Server存储过程会减慢每次执行的速度

时间:2012-02-04 14:51:20

标签: performance sql-server-2008 stored-procedures cursor

我有一个存储过程,可以使用一些游标进行许多选择和更新。

当我第一次执行该程序时,大约需要30秒。第二次执行大约需要1分钟。第三个约2分钟。

每次执行都会减慢程序。现在大约需要10分钟。

出了什么问题?

变量:

declare @StatistikStatus nvarchar(100)
declare @SQL as nvarchar(MAX)
declare @Datum  as nvarchar(50) --Datum im nvarchar Format
declare @Datumdatetime datetime --Datum im datetime Format
declare @tickethistorieID as uniqueidentifier
declare @id int --ID der Terminauswertung. Wird bei Einträgen benötigt, die pro Ticket mehrere Termine vereinbart haben.
declare @nextTermin datetime --Wird bei Einträgen benötigt, die pro Ticket mehrere Termine vereinbart haben.
declare @status nvarchar(100)
declare @statusdiff as nvarchar(100)
declare @vorStatus as nvarchar(100)
declare @lastid as int
declare @tickethistoriemerker nvarchar(40)
declare @statistikstatusmerker nvarchar(100)
DECLARE @TicketID uniqueidentifier

游标示例:

DECLARE C_TicketHistorie CURSOR FOR
    SELECT  
        dbo.TicketHistorie.TicketID,dbo.TicketHistorie.Datum,dbo.tickethistorie.tickethistorieid
    FROM 
        dbo.TicketHistorie INNER JOIN
        dbo.Status ON dbo.TicketHistorie.NeueStatusID = dbo.Status.StatusID
        INNER JOIN dbo.StatuszuStatistikStatus as s on s.status_ID = dbo.Status.statusid
        INNER JOIN dbo.StatistikStatus as ss on s.bewertung_id = ss.id
    WHERE     
    ss.id = 5 AND -- 5 = HNR Terminbestätigung
        (dbo.Status.Name = N'Termin vereinbart') 
     AND ((YEAR(dbo.TicketHistorie.Datum) >= 2011 and day(dbo.TicketHistorie.Datum) >= 27 and month(dbo.TicketHistorie.Datum) >= 12)or YEAR(dbo.TicketHistorie.Datum) >= 2012)

    ORDER BY TicketID,Datum asc
OPEN C_TicketHistorie;

FETCH NEXT FROM C_TicketHistorie into @TicketID,@Datumdatetime,@TickethistorieID
WHILE @@FETCH_STATUS = 0
BEGIN
--some inserts etc.
FETCH NEXT FROM C_TicketHistorie into @TicketID,@Datumdatetime,@TickethistorieID
END
CLOSE C_TicketHistorie
DEALLOCATE C_TicketHistorie

我有4个游标。 还有一些像这样的动态SQL

SET @SQL ='UPDATE Statistik.dbo.terminauswertungab27122011 SET ['
                SET @SQL =@SQL + @StatistikStatus+']='''
                SET @SQL =@SQL + cast(@TicketHistorieID as NVARCHAR(36))+''''
                SET @SQL =@SQL + ' WHERE ID = ' + cast(@ID as nvarchar) +' and ['+@StatistikStatus+'] IS NULL' 
                EXEC (@SQL)

我使用SSMS调用该程序。

在stp的开头我删除了插入的表。然后我做了插入。每次执行时表行都是相同的

1 个答案:

答案 0 :(得分:2)

首先,将光标声明更改为更高效的光标:

DECLARE C_TicketHistorie CURSOR
    LOCAL STATIC FORWARD_ONLY READ_ONLY
    FOR

接下来,您确定需要光标来进行这些操作吗?例如,您的更新似乎可以作为单个基于集合的操作而不是游标和动态SQL来完成,尤其是如果您知道可以由@StatistikStatus指示的列名称集合(由此确定,由方式?)。以下是如何一次性生成基于集合的动态SQL更新而不是游标:

DECLARE @sql NVARCHAR(MAX) = N'';

WITH x AS
(
    SELECT  
        -- why only use aliases for the tables you don't reference often?
        th.TicketID, th.Datum, th.tickethistorieid
    FROM 
        dbo.TicketHistorie AS th
        INNER JOIN dbo.Status AS st
          ON th.NeueStatusID = st.StatusID
        INNER JOIN dbo.StatuszuStatistikStatus as s 
          on s.status_ID = st.statusid
        INNER JOIN dbo.StatistikStatus as ss 
          on s.bewertung_id = ss.id
    WHERE     
      ss.id = 5 -- 5 = HNR Terminbestätigung 
      AND st.Name = N'Termin vereinbart'
     -- be smarter about date range queries!
      AND dbo.TicketHistorie.Datum >= '2011127'
)
SELECT @sql += N'UPDATE Statistik.dbo.terminauswertungab27122011 SET ['
       + @StatistikStatus+']='''
       + cast(@TicketHistorieID as NVARCHAR(36))+''''
       + ' WHERE ID = ' + cast(@ID as nvarchar) + ' -- nvarchar(WHAT)?
       and ['+@StatistikStatus+'] IS NULL;';

这里可能会有更多优化,但正如评论所暗示的那样,没有更多信息就很难做到。