SQL Server游标性能缓慢

时间:2012-02-15 16:46:33

标签: sql-server sql-server-2008-r2

我开始在sql server 2008中首次使用存储过程中的游标。我已经做了一些初步阅读,我知道它们有很大的性能限制。在我目前的情况下,我认为它们是必要的(我想在符号表中为每个股票代码运行多个存储过程。

编辑: 我将在每个符号上调用的sprocs大部分是插入操作来计算符号相关值,例如5天移动平均值,平均每日交易量,ATR(平均真实范围)。这些值中的大部分将根据每日定价和数量表中的数据进行计算...我希望简化对冗余检索的数据值的检索,否则...例如,我想得到每个值将每日定价和卷数据符号转换为表变量...然后将临时表传递给调用我刚刚提到的每个聚合函数的存储过程。希望有意义......

所以我的初始“外部循环”基于游标的存储过程在下面..它在几分钟后超时,而没有返回到输出窗口。

ALTER PROCEDURE dbo.sprocSymbolDependentAggsDriver2

    AS

    DECLARE @symbol nchar(10)
    DECLARE symbolCursor CURSOR
    STATIC FOR
    SELECT Symbol FROM tblSymbolsMain ORDER BY Symbol

    OPEN symbolCursor
    FETCH NEXT FROM symbolCursor INTO @symbol
    WHILE @@FETCH_STATUS = 0
        SET @symbol = @symbol + ': Test.'
        FETCH NEXT FROM symbolCursor INTO @symbol

    CLOSE symbolCursor
    DEALLOCATE symbolCursor

当我在没有@symbol局部变量的情况下运行它并在while循环中消除它的赋值时,它似乎运行正常。在该任务中是否明显违反了绩效最佳做法?感谢..

4 个答案:

答案 0 :(得分:5)

  

"在我目前的情况下,我认为他们是必要的(我想要多次运行)   符号表中每个股票代码的存储过程。"

很少需要游标。

从上面的例子中,我认为一个简单的WHILE循环很容易取代你的光标。改编自SQL Cursors - How to avoid them(我最喜欢的SQL书签之一)

-- Create a temporary table...
CREATE TABLE #Symbols (
 RowID int IDENTITY(1, 1), 
 Symbol(nvarchar(max))
)
DECLARE @NumberRecords int, @RowCount int
DECLARE @Symbol nvarchar(max)

-- Get your data that you want to loop over
INSERT INTO #Symbols (Symbol)
SELECT Symbol
FROM tblSymbolsMain 
ORDER BY Symbol

-- Get the number of records you just grabbed
SET @NumberRecords = @@ROWCOUNT
SET @RowCount = 1


-- Just do a WHILE loop.  No cursor necessary.
WHILE @RowCount <= @NumberRecords
BEGIN
 SELECT @Symbol = Symbol
 FROM #Symbols
 WHERE RowID = @RowCount

 EXEC <myProc1> @Symbol
 EXEC <myProc2> @Symbol
 EXEC <myProc3> @Symbol

 SET @RowCount = @RowCount + 1
END


DROP TABLE #Symbols

答案 1 :(得分:2)

您并不需要所有显式游标爵士来构建字符串。这可能是一种更有效的方法:

DECLARE @symbol NVARCHAR(MAX) = N'';

SELECT @symbol += ': Test.'
    FROM dbo.tblSymbolsMain 
    ORDER BY Symbol;

虽然我怀疑你确实想看到符号的名称,例如

DECLARE @symbol NVARCHAR(MAX) = N'';

SELECT @symbol += N':' + Symbol
    FROM dbo.tblSymbolsMain 
    ORDER BY Symbol;

有一点需要注意的是,虽然您通常会遵守要遵守的命令,但并不能保证。所以如果你想坚持光标,至少要按如下方式声明光标:

DECLARE symbolCursor CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
...

在我看来,NCHAR(10)似乎还不足以保存您尝试填充的数据,除非您只有一行(这就是我选择NVARCHAR(MAX)的原因)。< / p>

我同意Abe ...很可能你不需要为光标中的每一行触发存储过程,而是建议解决方法(这几乎肯定会更有效),我们' d必须了解这些存储过程实际上做了什么。

答案 2 :(得分:2)

你需要在这里结束:

WHILE @@FETCH_STATUS = 0 BEGIN
    SET @symbol = @symbol + ': Test.'
    FETCH NEXT FROM symbolCursor INTO @symbol
END

还可以尝试使用DECLARE symbolCursor CURSOR LOCAL READ_ONLY FORWARD_ONLY代替STATIC来提高效果。

答案 3 :(得分:0)

在阅读完所有建议之后,我最终做了一些老技巧,它创造了奇迹!

我有这个光标,需要花费近3分钟才能运行,而封闭的查询是即时的。我有其他更复杂的游标数据库只需要1秒或更短的时间,所以我排除了使用游标的全局问题。我的解决方案:

  1. 分离有问题的数据库,但请确保勾选更新统计信息。
  2. 附加数据库并检查性能
  3. 这似乎有助于优化所有性能参数,而无需详细的努力。我正在使用SQL Express 2008 R2。

    想知道你的经历。

相关问题