【发布时间】:2013-12-05 17:35:59
【问题描述】:
我有一个旧的存储过程试图创建一个游标来遍历查询中的每一行。性能相当差。然后我检查查询计划,大部分成本(> 47%)都在对象[tempdb].[CWT_PrimaryKey] 上。这个对象是由存储过程中创建的游标创建的。不确定如何提高这种情况下的性能,因为在 SQL Server 创建的tempdb 中无法对此对象执行任何操作。
存储过程中的伪代码如:
BEGIN TRY
BEGIN TRANSACTION
declare mycusorr local fast_forward
for SELECT * From MyTab Where a=b;
open mycusorr;
fetch next from mycusorr into @v1, @v2, ...;
while @@fetch_status = 0
begin
--some query to check rules from different tables
Update AnotherTab Set column=value where id = @v1;
if (there is error)
insert error to error user log table;
End
close mycusorr;
deallocate mycusorr;
COMMIT;
END TRY
BEGIN CATCH
close mycusorr;
deallocate mycusorr;
SELECT ERROR_NUMBER() AS ErrorNumber,ERROR_MESSAGE() AS ErrorMessage;
ROLLBACK TRAN;
END CATCH
MyTab 上没有主键,但在条件中使用的列上创建了索引。
Mytab 大约有 10,000 行。运行存储过程需要3个多小时甚至没有完成。如果我从存储过程中删除事务,它会很快。
当我用SP_lock检查锁时,在循环中有更新子句的表的键或页面上有超过10,000个X或IX锁。
【问题讨论】:
-
循环部分发生了什么? 99% 的时间可以将光标重写为基于集合的解决方案。这样做的唯一方法是您向我们提供所有代码
-
使用循环,只需尝试使用游标中的数据更新另一个表。
-
如果您提供您的实际代码,我可能会提供帮助。没有它,问题的答案很简单:“重写以不使用光标”。
-
也许我在这里遗漏了一些东西,但为什么你需要一个光标在第一个位置?您尝试执行的更新可以在 1 个更新语句中轻松完成,并在
MyTab和AnotherTab表之间连接。 -
你为什么要使用光标?如果您进入 catch 块,为什么您只费心关闭/解除分配?
标签: sql performance sql-server-2008 sql-server-2008-r2