游标性能

gru*_*ber 1 sql t-sql sql-server sql-server-2008

我有一个非常大的脚本,它使用游标和嵌套游标.

我遇到了性能问题,我发现脚本中的最后一条指令完成了main while循环占用了大部分时间:

SET STATISTICS TIME ON

FETCH NEXT FROM OldMetaOffer_cursor
INTO @MetaOfferId, @CustomerId, @OfferName, @CheckedOutById, @CheckOutDate, @LastOfferStatusId, @LastCalculationNumber, @CreatedByDisplayName, @CreatedById, @CreateDate, @CoordinatorId, @CoordinatorDate, @CentralAnalystId, @CentralAnalystDate, @DeployUserId, @DeploymentDate, @OwnerId;

SET STATISTICS TIME OFF
Run Code Online (Sandbox Code Playgroud)

SQL Server执行时间:

  • CPU时间= 0 ms,经过时间= 0 ms.
  • SQL Server执行时间:
  • CPU时间= 4328 ms,经过时间= 4335 ms.

它需要超过4秒,而一步完成需要4,6秒

表MetaOffer有大约150 k行但我在8,5 k行上使用游标.(我在开头过滤行).

有没有办法改善这种糟糕的表现?

在循环开始时我有:

DECLARE   @MetaOfferId uniqueidentifier     
    , @MetaOfferTypeId int
    , @CustomerId  uniqueidentifier         -- CustomerId
    , @OfferName nvarchar(50)               -- OfferName
    , @CheckedOutById int                   -- CheckOutById
    , @CheckOutDate datetime                -- CheckOutDate
    , @LastOfferStatusId int                -- LastProcessStatusId            
    , @LastCalculationNumber nvarchar(20)   -- LastCalculationNumber
    , @CreatedByDisplayName nvarchar(300)   -- CreatedByDisplayName
    , @CreatedById int                      -- CreatedById
    , @CreateDate datetime                  -- CreateDate
    , @CoordinatorId int                    -- CoordinatorId
    , @CoordinatorDate datetime             -- CoordinatorDate
    , @CentralAnalystId int                 -- CentralAnalystId
    , @CentralAnalystDate datetime          -- CentralAnalystDate
    , @DeployUserId int                     -- DeployUserId
    , @DeploymentDate datetime              -- DeploymentDate
    , @OwnerId int                          -- OwnerId
    -- id statusu po zmapowaniu
    , @NewLastOfferStatusId int             



DECLARE OldMetaOffer_cursor CURSOR FOR
SELECT  MetaOfferId, CustomerId, OfferName, CheckedOutById, CheckOutDate, LastOfferStatusId, LastCalculationNumber, CreatedByDisplayName, CreatedById, 
        CreateDate, CoordinatorId, CoordinatorDate, CentralAnalystId, CentralAnalystDate, DeployUserId, DeploymentDate, OwnerId

FROM [Other].[dbo].[MetaOffer] MO where 
    exists 
    (select * from [Other].[dbo].[OfferHistoryItem] 
    where MetaOfferId = MO.MetaOfferId  and NewStatusId = 9 and DiscountId is null and KoosOfferId is null) 
Run Code Online (Sandbox Code Playgroud)

也许有一个问题,在下一次获取此查询再次进行?结果在任何地方都没有缓冲.如果是这样,我可以通过任何方式获得该查询的结果并对数据进行操作而不对每个循环步骤进行查询?

HLG*_*GEM 5

由于你遗漏了问题最重要的部分(游标实际上做了什么),我只是给你这个参考,希望能告诉你如何在没有游标的情况下完成你的任务.游标表现极差,如果存在任何其他替代方案,则不应使用游标.我曾经通过移除光标将过程从45分钟更改为不到1分钟,另一个过程从24小时变为大约30分钟.使用游标的原因很少,很多不使用游标.它们是最后的技术,而不是你尝试的第一件事.

http://wiki.lessthandot.com/index.php/Cursors_and_How_to_Avoid_Them

  • 这在很大程度上是重点 - 如果你没有通过游标循环,你就不会碰到游标的FETCH语句所遇到的任何开销. (3认同)