2012-07-25 186 views
1

我有一個存儲過程,它接受三個參數並使用遊標來收集數據。奇怪的是運行SP所需的時間。有時需要5-10分鐘才能運行並返回300行。通過在遊標內運行單個查詢,數據似乎很快返回。我有點難以理解爲什麼整體運行需要這麼長時間。如果任何人都可以指出我可能需要查詢的任何錯誤或修復,我將不勝感激。遊標查詢速度慢,但個別查詢速度快

USE [AW] 
GO 
/****** Object: StoredProcedure [dbo].[Issue_Report] Script Date: 07/25/2012 15:06:04 ******/ 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
ALTER PROCEDURE [dbo].[Issue_Report] 
    @MinDate DateTime, 
    @MaxDate DateTime, 
    @PSNumParam varchar(50) 
AS 
BEGIN 
-- SET NOCOUNT ON added to prevent extra result sets from 
-- interfering with SELECT statements. 
SET NOCOUNT ON; 

-- Setup Temp Table 
DECLARE @TempIssueData TABLE 
(
    [Date]     datetime, 
    [SerialNum]    varchar(MAX), 
    [LotNum]    varchar(MAX), 
    [CatalogNum]   varchar(MAX), 
    [PSNum]     varchar(MAX), 
    [Description]   varchar(MAX), 
    [ORCaseNum]    varchar(MAX), 
    [UserName]    varchar(MAX), 
    [Issued_From]   varchar(MAX), 
    [Issued_To]    varchar(MAX), 
    [Surgical_Specalty]  varchar(MAX), 
    [surgeon]    varchar(50), 
    [SurgeryEndDate]  datetime 
) 

-- Declare Variables (easier for debugging) 
DECLARE @StartDate   datetime = @MinDate 
DECLARE @EndDate   datetime = @MaxDate 
DECLARE @Date    datetime 
DECLARE @SurgeryEndDate  datetime 
DECLARE @SerialNum   varchar(MAX) 
DECLARE @LotNum    varchar(MAX) 
DECLARE @CatalogNum   varchar(MAX) 
DECLARE @PSNum    varchar(MAX) 
DECLARE @Description  varchar(MAX) 
DECLARE @ORCaseNum   varchar(MAX) 
DECLARE @UserName   varchar(MAX) 
DECLARE @Issued_From  varchar(MAX) 
DECLARE @Issued_To   varchar(MAX) 
DECLARE @Surgical_Specialty varchar(MAX) 
DECLARE @Surgeon   varchar(50) 
DECLARE @ItemID    uniqueidentifier 
DECLARE @LocationID   uniqueidentifier 
DECLARE @UserID    uniqueidentifier 
DECLARE @UnitLocation  uniqueidentifier 

-- Fix EndDateTime to include the whole day 
IF(SELECT CONVERT(varchar,@MaxDate, 108) AS TimeOnly) = '00:00:00' 
BEGIN 
    SET @EndDate = DATEADD(SECOND, 86400,@MaxDate) 
END 

-- Setup Parameters 
IF (@PSNumParam ='') BEGIN SET @PSNumParam = NULL END 

-- Setup Cursor 
DECLARE curs_GetIssueData CURSOR FOR 
    SELECT item.ID, item.SerialNumber, item.LotNumber, items.PartNumber, items.CrossRefID, items.Description, item.LocationID 
    FROM dbo.item WITH (INDEX(Stat_LastUpdated)) INNER JOIN dbo.items ON item.ItemID = items.ID 
    WHERE (dbo.item.Stat = 3) AND (dbo.item.LastUpdated BETWEEN @StartDate AND @EndDate) AND Tracking='1' 
    AND CrossRefID = ISNULL(@PSNumParam, CrossRefID) 

    OPEN curs_GetIssueData 

    -- Start Reading 
    FETCH NEXT FROM curs_GetIssueData INTO @ItemID, @SerialNum, @LotNum, @CatalogNum, @PSNum, @Description, @LocationID 
     WHILE (@@FETCH_STATUS = 0) 
      -- BEGIN WHILE 
      BEGIN 

       SET @Issued_From = NULL 
       BEGIN 
        SELECT @Issued_From = ISNULL(Locations.Name, 'N/A') 
        FROM dbo.Locations 
        WHERE Locations.ID = @LocationID 
       END 

       BEGIN 
        -- Setup Cursor 
        DECLARE curs_GetTransData CURSOR FOR 
         SELECT TOP 1 ORCaseNumber, SurgicalSpecialty, UserID, ORNumber, TransDate, Surgeon, EndDateTime 
         FROM dbo.transactions 
         WHERE transactions.ItemID = @ItemID AND transactions.TransactionTypeID in (8,9,10) AND transactions.TransDate BETWEEN @StartDate and @EndDate 
         ORDER BY transactions.TransDate desc 

         OPEN curs_GetTransData 

         -- Start Reading 
         FETCH NEXT FROM curs_GetTransData INTO @ORCaseNum, @Surgical_Specialty, @UserID, @Issued_To, @Date, @Surgeon, @SurgeryEndDate 
          WHILE (@@FETCH_STATUS = 0) 
           -- BEGIN GetTransData WHILE 
           BEGIN 
            -- Reset UserName 
            SET @UserName = NULL 
            SET @UnitLocation = NULL 

            BEGIN 
             SELECT @UnitLocation = Unit.LocationID 
             FROM dbo.Unit 
             WHERE UnitType='4' and Unit.LocationID = @LocationID 
            END 

            -- Check to see if UserID is NULL 
            IF @UserID IS NULL AND @UnitLocation IS NOT NULL 
            BEGIN 
             SET @UserName = 'CORONA'  
            END 

            ELSE 
            BEGIN 
             SELECT @UserName = dbo.users.LastName + ', ' + dbo.users.FirstName 
             FROM dbo.users 
             WHERE users.ID = @UserID 
            END 

           FETCH NEXT FROM curs_GetTransData INTO @ORCaseNum, @Surgical_Specialty, @UserID, @Issued_To, @Date, @Surgeon, @SurgeryEndDate 
           -- END GetTransData WHILE 
           END 

         -- CLEANUP 
         CLOSE curs_GetTransData 
         DEALLOCATE curs_GetTransData 
       END 

       BEGIN 
        INSERT INTO @TempIssueData 
        VALUES(
         @Date, 
         @SerialNum, 
         @LotNum, 
         @CatalogNum, 
         @PSNum, 
         @Description, 
         @ORCaseNum, 
         @UserName, 
         @Issued_From, 
         @Issued_To, 
         @Surgical_Specialty, 
         @Surgeon, 
         @SurgeryEndDate 
        ) 
       END 

      -- Fetch next record  
      FETCH NEXT FROM curs_GetIssueData INTO @ItemID, @SerialNum, @LotNum, @CatalogNum, @PSNum, @Description, @LocationID 

      -- END WHILE 
      END 

     -- CLEANUP 
     CLOSE curs_GetIssueData 
     DEALLOCATE curs_GetIssueData 

SELECT * FROM @TempIssueData ORDER BY [Date] Desc, [Issued_From] 
END 
+1

你檢查了[實際查詢執行計劃](http://www.simple-talk.com/sql/performance/execution-plan-基本/)? (如果沒有數據洞察力,以及確切哪部分緩慢,這很難回答。) – Andomar 2012-07-25 19:28:46

+7

嵌套遊標?哦,我的,哦,我的,哦,我的。至少將遊標聲明更改爲'DECLARE CURSOR LOCAL STATIC FORWARD_ONLY READ_ONLY FOR ...' – 2012-07-25 19:29:02

+0

檢查查詢計劃。如果它們不同,你可能會處理不良的參數嗅探。如果是這樣,你可以A)嘗試添加WITH RECOMPILE或B)聲明臨時變量,填入那些臨時變量中的參數,然後僅使用臨時變量。 – Stu 2012-07-25 19:29:09

回答

0

顯然, 您創建一個不是Temptable 需要4次臨時表
1.選擇查詢執行時間
在光標
3.將查詢執行 2.將查詢執行時間更最小時間TempTeble +光標運行
4.選擇Temeptable執行時間相同,1次

嘗試刪除光標並選擇查詢加入不與遊標 它可能會生成這樣的sql select查詢