我开始在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循环中消除它的赋值时,它似乎运行正常。在该任务中是否明显违反了绩效最佳做法?感谢..
答案 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秒或更短的时间,所以我排除了使用游标的全局问题。我的解决方案:
这似乎有助于优化所有性能参数,而无需详细的努力。我正在使用SQL Express 2008 R2。
想知道你的经历。