Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/76.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 游标性能_Sql_Sql Server_Tsql_Sql Server 2008 - Fatal编程技术网

Sql 游标性能

Sql 游标性能,sql,sql-server,tsql,sql-server-2008,Sql,Sql Server,Tsql,Sql Server 2008,我有一个相当大的脚本,它使用游标和嵌套的游标 我面临性能问题,我发现脚本中完成主while循环的最后一条指令占用了大部分时间: SET STATISTICS TIME ON FETCH NEXT FROM OldMetaOffer_cursor INTO @MetaOfferId, @CustomerId, @OfferName, @CheckedOutById, @CheckOutDate, @LastOfferStatusId, @LastCalculationNumber, @Creat

我有一个相当大的脚本,它使用游标和嵌套的游标

我面临性能问题,我发现脚本中完成主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
SQL Server执行时间:
  • CPU时间=0毫秒,运行时间=0毫秒
  • SQL Server执行时间:
  • CPU时间=4328毫秒,运行时间=4335毫秒
它需要4秒以上,而一步总共需要4,6秒

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

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

在循环开始时,我有:

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) 

可能是因为在下一次提取时再次执行此查询时出现了问题?结果不会在任何地方缓冲。如果是这样的话,我有没有办法兑现该查询的结果并对数据进行操作,而不必在每个循环步骤上进行查询?

游标的速度非常慢。嵌套游标甚至更慢。除此之外,我们还需要看到更多的具体信息来提供有用的建议。

光标速度非常慢。嵌套游标甚至更慢。除此之外,我们还需要看到更多的具体信息来提供有用的建议。

如果您查看任何合理的SQL Server当前版本的CURSOR文档,我想还有其他几个RDBMS,您会发现,它的状态不使用游标和一个示例,它们仅用于向后兼容

有很多方法可以避免它们,但这取决于您使用的数据库服务器

例如,可以使用临时表:

SELECT 
  [ID], [col1], [col2] 
INTO
  #stuff
WHERE
  [col1] LIKE '%something%'

DECLARE @id int, @c1 varchar(32), @c2 varchar(32)

SELECT TOP 1 @id = [ID], @c1 = [col1], @c2 = [col2]
FROM #stuff

WHILE @@ROWCOUNT > 0
BEGIN
  -- do something, say execute a stored procedure, for each row
  EXEC someproc @id, @c1, @c2

  SELECT TOP 1 @id = [ID], @c1 = [col1], @c2 = [col2]
  FROM #stuff
  WHERE [ID] > @id
END
根据代码的功能和使用的数据库,可能会有更有效的解决方案可用,但是临时表将提供比游标更大的改进


如果是在SQL Server上,请注意,如果您编写了访问表的标量函数(实际上是执行SELECT语句或调用其他执行语句的函数),则此类函数实际上会成为游标-因此,请尽可能避免使用它。

如果您查看任何合理的SQL Server当前版本的游标文档,我认为还有一些其他的RDBMS,你们会发现它的状态不使用游标和一个示例,它们只是为了向后兼容

有很多方法可以避免它们,但这取决于您使用的数据库服务器

例如,可以使用临时表:

SELECT 
  [ID], [col1], [col2] 
INTO
  #stuff
WHERE
  [col1] LIKE '%something%'

DECLARE @id int, @c1 varchar(32), @c2 varchar(32)

SELECT TOP 1 @id = [ID], @c1 = [col1], @c2 = [col2]
FROM #stuff

WHILE @@ROWCOUNT > 0
BEGIN
  -- do something, say execute a stored procedure, for each row
  EXEC someproc @id, @c1, @c2

  SELECT TOP 1 @id = [ID], @c1 = [col1], @c2 = [col2]
  FROM #stuff
  WHERE [ID] > @id
END
根据代码的功能和使用的数据库,可能会有更有效的解决方案可用,但是临时表将提供比游标更大的改进


如果是在SQL Server上,请注意,如果您编写了访问表的标量函数(实际上是执行SELECT语句或调用其他执行语句的函数),则此类函数实际上会成为游标-因此请尽可能避免使用它。

因为您忽略了问题的最重要部分(游标实际做的事情)我将简单地给你这个参考,希望能向你展示如何在没有光标的情况下完成你的任务。游标的性能非常差,如果存在其他替代方法,则不应使用游标。我曾经通过移除一个光标将一个过程从45分钟改为不到一分钟,另一个过程从24小时改为30分钟左右。使用光标的理由很少,不使用光标的理由很多。它们是最后的手段,而不是你尝试的第一件事


由于您遗漏了问题的最重要部分(游标实际做什么),我将简单地为您提供此参考,希望能向您展示如何在没有游标的情况下完成任务。游标的性能非常差,如果存在其他替代方法,则不应使用游标。我曾经通过移除一个光标将一个过程从45分钟改为不到一分钟,另一个过程从24小时改为30分钟左右。使用光标的理由很少,不使用光标的理由很多。它们是最后的手段,而不是你尝试的第一件事


这取决于你用光标做什么,任何人都可以提供一个性能更好的替代解决方案。这取决于你用光标做什么,任何人都可以提供一个性能更好的替代解决方案。但只有这条指令需要这么多时间,所以我相信我在循环中做什么都无关紧要。我将光标更改为您提供的解决方案,性能从8分钟提高到7,5分钟:)但只有这条指令需要这么多时间,所以我相信不管我在循环中做什么,我从游标改为您提供的解决方案,性能从8分钟提高到7,5分钟:)我不认为循环中的内容真的很重要,因为根据我所写的,从游标获取下一步到。。。占用大部分时间这主要是问题所在——如果不通过游标循环,则不会命中游标的FETCH语句所命中的任何开销。@gruber,游标一次只工作一行,而不是以基于集合的方式工作,因此当然,获取每一行是耗时的部分,因此不应该使用它们。请看这篇文章。你使用了一种糟糕的说唱技巧,显然你不想听。但如果我们不告诉你使用更好的技术,那我们就是失职了。游标只适用于一些非常有限的用途(一般来说,DBA和高级程序员只应该使用游标,他们知道自己在做什么,以及游标对性能的影响),但几乎不应该被需要或使用。我认为循环内部的内容并不重要,因为根据我写的“从游标获取下一步内容到…”。。。占用大部分时间这主要是问题所在——如果不通过游标循环,则不会命中游标的FETCH语句所命中的任何开销。@gruber,游标一次只能工作一行