【问题标题】:Cursors are taking time on my Stored Procedure?光标在我的存储过程上花费时间?
【发布时间】:2013-09-26 04:12:50
【问题描述】:

我在 SQL Server 2008 r2 下的存储过程中有两个游标。执行存储过程时它们会浪费我的时间吗? 我有两张桌子

##TEMP

CatalogID    Value
34567         80
34848         100
34725         40


##Temp1

   Name    Percentage
     A       25
     B       25
     C       25
     D       25

通过使用两个临时表,我将数据插入到目录表中并删除输入的目录 ID 和值。

catalogtable



 CatalogID    name    value

  34567          A      20
  34567          B      20
  34567          C      20
  34567          D      20
  34848          A      25
  34848          B      25
  34848          C      25
  34848          D      25
  34725          A      10
  34725          B      10
  34725          C      10
  34725          D      10

我的光标是

DECLARE Cur_Rotation CURSOR
FOR 
                  SELECT CatalogId,Value FROM ##TEMP
                   DECLARE  @CatalogId INT
                   DECLARE @Value [decimal](5, 2)
                   OPEN Cur_Rotation
                   FETCH NEXT FROM Cur_Rotation INTO @CatalogId,@Value
                   While @@FETCH_STATUS = 0
BEGIN
           DECLARE Cur_Inner CURSOR
           FOR
                              SELECT Name,Percentage FROM ##Temp1
                              DECLARE @Name VARCHAR(50)
                              DECLARE @Percentage [decimal](5, 2)
                              OPEN Cur_Inner
                              FETCH NEXT FROM Cur_Inner   INTO @Name,@Percentage
                              While @@FETCH_STATUS = 0
BEGIN

                             DECLARE @Value1 [decimal](5, 2) 

                             SET @Value=@Value1*(@Percentage/100.00)
               DELETE FROM  CatalogDetails WHERE CatalogId=@CatalogId  and name=@name
                INSERT INTO CatalogDetails (name,RDDRotPcent,CatalogId)
                                VALUES (@name,@Value1,@CatalogId) 
        FETCH NEXT FROM Cur_Inner  INTO @Name,@Percentage
END
CLOSE Cur_Inner
DEALLOCATE Cur_Inner 
                        FETCH NEXT FROM Cur_Rotation INTO @CatalogId,@Value
END                        

CLOSE Cur_Rotation
DEALLOCATE Cur_Rotation
END

有没有机会使用任何逻辑来跳过游标。当时我的查询执行需要时间,CatalogID 将是数千。所以有没有机会更改我的 SCRIPT 以避免游标。

【问题讨论】:

  • 如果可能,请始终尝试使用 SQL 方式来做某事,而不是使用游标。如果您可以使用一条或多条 SQL 语句执行相同的操作,则速度会快几个数量级。
  • 你能用文字解释一下你想要实现的 sp 的目的/目的吗?我认为我们可以消除光标并使其变得非常简单
  • Value1 永远不会被初始化并且总是导致@Value 为空

标签: sql-server tsql stored-procedures sql-server-2008-r2 cursor


【解决方案1】:

在您的情况下,您可以在没有游标甚至没有递归查询的情况下执行此操作:

insert into catalogtable (CatalogID, name, value)
select
    t.CatalogID,
    t1.name,
    t.Value * t1.Percentage / 100.00
from #TEMP as t
    cross join #TEMP1 as t1

sql fiddle demo

【讨论】:

  • 唯一缺少的是 DELETE FROM CatalogDetails WHERE CatalogId=@CatalogId 和 name=@name 部分
【解决方案2】:

我相信这可以解决您的整个问题

--Prepare data

DECLARE @Temp1 AS TABLE
(
    CatalogId INT,
    VALUE DECIMAL(19,5)
    )

    INSERT INTO @Temp1 SELECT 34567, 80
    INSERT INTO @Temp1 SELECT 34848, 100
    INSERT INTO @Temp1 SELECT 34725, 40


DECLARE @CatalogDetails AS TABLE
(Id INT PRIMARY KEY IDENTITY(1,1), NAME NVARCHAR(100), RDDRotPcent DECIMAL(19,5), CatalogId INT)

INSERT INTO @CatalogDetails SELECT 'A', .99, 12345
INSERT INTO @CatalogDetails SELECT 'B', .99, 34567


DECLARE @Temp2 AS TABLE
( NAME NVARCHAR(100),
 Percentage DECIMAL(19,5))

 INSERT INTO @Temp2 SELECT 'A', .25
 INSERT INTO @Temp2 SELECT 'B', .25
 INSERT INTO @Temp2 SELECT 'C', .25
 INSERT INTO @Temp2 SELECT 'D', .25


 DECLARE @Catalog AS TABLE
 (CatalogId INT, NAME NVARCHAR(100), VALUE DECIMAL(19,5))
--Fill Catalog with new Data
 INSERT INTO @Catalog

         SELECT CatalogId, NAME, Value * Percentage FROM @Temp1, @Temp2

--Delete Old Values
         DELETE FROM @CatalogDetails WHERE Id IN (SELECT Id FROM @CatalogDetails CD Inner JOIN @Catalog C ON CD.CatalogId = C.CatalogId AND CD.Name = C.NAME)

--Insert New Values

         INSERT INTO @CatalogDetails SELECT Name, Value, CatalogId FROM @Catalog

--View End Result
         SELECT * FROM @CatalogDetails

【讨论】:

    【解决方案3】:

    不太确定它有多大帮助。但是您可以尝试这样的方法来避免光标:-

    DECLARE @number_rows     int
    DECLARE @count           int
    DECLARE @selected     int
    
    DECLARE @table1 TABLE (Id int not null primary key identity(1,1), col1 int )  
    INSERT into @table1 (col1) SELECT col1 FROM table2
    SET @number_rows=@@ROWCOUNT
    
    SET @count=0
    WHILE @count<@number_rows     
    BEGIN
        SET @count=@count+1
        SELECT 
            @selected=col1
            FROM @table1
            WHERE Id=@count
    
        --do your stuff here--
    
    END
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-25
      • 1970-01-01
      • 2019-12-20
      • 2012-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多