Sql 游标性能
我有一个相当大的脚本,它使用游标和嵌套的游标 我面临性能问题,我发现脚本中完成主while循环的最后一条指令占用了大部分时间: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
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毫秒
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,游标一次只能工作一行