2012-02-15 76 views
2

我開始使用sql server 2008存儲過程中的第一次使用遊標。我已經做了一些初步的閱讀,並且我明白它們有顯着的性能限制。在我目前的情況下,我認爲他們是必要的(我想要爲符號表中的每個股票符號運行多個存儲過程。SQL服務器光標性能低下

編輯: 我會在每個符號上調用的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循環中的賦值,它似乎運行良好。是否明顯違反該作業中的績效最佳做法?謝謝..

+3

你試圖運行的存儲過程是做什麼的? – 2012-02-15 16:49:36

+0

@AbeMiessler我剛剛編輯我的帖子來描述內部sprocs,thx .. – StatsViaCsh 2012-02-15 21:01:26

回答

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))。

,我和安倍晉三同意...這是很可能的,你不需要觸發一個存儲過程中的遊標的每一行,但建議圍繞該方式(這幾乎肯定會更有效率),我們必須瞭解那些存儲過程實際上做了什麼。

+0

謝謝..我現在正在查看答案,我正在編輯我原來的帖子來描述一些我將使用的sprocs,「爲每個「符號.. – StatsViaCsh 2012-02-15 20:48:10

+0

順便說一句在我的帖子中的代碼只是一個測試,以查看遊標迭代的輸出..我的成品將只是檢索一個符號,並將其傳遞到另一個存儲過程。 – StatsViaCsh 2012-02-15 21:36:01

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以提高性能。

+0

+1好抓,我錯過了'BEGIN/END'丟失。 – 2012-02-15 17:08:23

3

「以我目前的情況下,我認爲他們是必要的(我想爲一個符號表中的每個股票代碼運行多個 存儲過程。」

光標是很少需要。

從你上面的例子中,我認爲一個簡單的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 
+0

爲什麼你認爲while循環不是遊標?或者它會表現更好?我做了一些關於此的博客。 http://sqlblog.com/blogs/aaron_bertrand/archive/2012/01/26/the-fallacy-that-a-while-loop-isn-ta-cursor.aspx – 2012-02-15 17:09:41

+0

@womp感謝您的時間,並感謝鏈接.. – StatsViaCsh 2012-02-15 22:12:42

0

閱讀所有的建議後,我結束了做一些老把戲,它創造了奇蹟!

我有這個遊標需要將近3分鐘才能運行,而封閉查詢是即時的。我有其他更復雜的遊標數據庫,只需要1秒或更少的時間,所以我排除了使用遊標的全局問題。我的解決方案:

  1. 分離有問題的數據庫,但確保您勾選更新統計信息。
  2. 附加數據庫和查詢性能

這似乎有助於優化沒有詳細努力的所有性能參數。我正在使用SQL Express 2008 R2。

想知道您的經驗。