2012-07-25 240 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查询