2009-06-08 34 views
5

我想知道您在使用現有代碼中的SQL Server遊標替換過程中的體驗,或者您如何解決程序員使用遊標解決問題的方法,以及它是否基於set-based。更換光標有哪些不同的方法?

光標被用來解決什麼問題?你是如何替換光標的?

回答

5

嘗試永不循環,處理數據集。

您可以一次插入,更新,刪除多行。這裏插入一個多行示例:

INSERT INTO YourTable 
     (col1, col2, col3, col4) 
    SELECT 
     cola, colb+Colz, colc, @X 
     FROM .... 
      LEFT OUTER JOIN ... 
     WHERE... 

當看一個循環時,看看它在裏面做了什麼。如果只是插入/刪除/更新,請重新編寫以使用單個命令。如果有IF,請查看它們是否可以是CASE語句或WHERE條件插入/刪除/更新。如果是這樣,請刪除循環並使用set命令。

我採取了循環,並用基於集合的命令替換它們,並將執行時間從幾分鐘減少到幾秒鐘。我已經採用了許多嵌套循環和過程調用的過程,並保留了循環(不可能只使用插入/刪除/更新),但我刪除了光標,並且看到鎖定/阻塞較少,並且性能大幅提升。這裏有兩個循環的方法是優於光標循環...

,如果你有循環,在一組做這樣的事情:

--this looks up each row for every iteration 
DECLARE @msg VARCHAR(250) 
DECLARE @hostname sysname 

--first select of currsor free loop 
SELECT @hostname= min(RTRIM(hostname)) 
    FROM master.dbo.sysprocesses (NOLOCK) 
    WHERE hostname <> '' 

WHILE @hostname is not null 
BEGIN 
    set @msg='exec master.dbo.xp_cmdshell "net send ' 
     + RTRIM(@hostname) + ' ' 
     + 'testing "' 
    print @msg 
    --EXEC (@msg) 

    --next select of cursor free loop 
    SELECT @hostname= min(RTRIM(hostname)) 
     FROM master.dbo.sysprocesses (NOLOCK) 
     WHERE hostname <> '' 
     and hostname > @hostname 
END 

,如果你有一個合理的組項目(不十萬)來循環你可以這樣做:

--this will capture each Key to loop over 
DECLARE @msg VARCHAR(250) 
DECLARE @From int 
DECLARE @To  int 
CREATE TABLE #Rows 
(
    RowID  int not null primary key identity(1,1) 
    ,hostname varchar(100) 
) 

INSERT INTO #Rows 
SELECT DISTINCT hostname 
    FROM master.dbo.sysprocesses (NOLOCK) 
    WHERE hostname <> '' 
SELECT @From=0,@[email protected]@ROWCOUNT 

WHILE @From<@To 
BEGIN 
    SET @[email protected]+1 

    SELECT @msg='exec master.dbo.xp_cmdshell "net send ' 
     + RTRIM(hostname) + ' ' 
     + 'testing "' 
     FROM #Rows WHERE [email protected] 
    print @msg 
    --EXEC (@msg) 
END 
2

那麼,通常一個用於程序編程的應用程序開發者將不再習慣 - 儘量以程序化方式處理所有事情,即使在SQL中也是如此。

大多數情況下,具有正確參數的SELECT可能會執行 - 或者您正在處理UPDATE語句。

問題的關鍵在於:您需要開始在集合操作中思考並告訴RDBMS您想要完成的任務 - 而不是一步一步地完成。

很難給出一個「正確的」答案......你幾乎不得不用一個具體的例子來展示它。

Marc

0

我寫了一些代碼來計算與給定年份相關的財務數據的運行總計。在每個季度,我必須將當前季度的值添加到運行總計,同時適當地處理NULL,以便在當前季度的值爲NULL時延續上個季度的運行總計。

最初,我是用光標做的,從功能的角度來看,這符合業務需求。從技術角度來看,它變成了一個表演停止者,因爲隨着數據量的增加,代碼的指數時間變長了。解決方案是用滿足功能要求的相關子查詢替換遊標,並消除任何性能問題。

希望這有助於

比爾

4

我已經更換了一些光標與WHILE循環。

DECLARE @SomeTable TABLE 
(
    ID int IDENTITY (1, 1) PRIMARY KEY NOT NULL, 
    SomeNumber int, 
    SomeText varchar 
) 

DECLARE @theCount int 
DECLARE @theMax int 

DECLARE @theNumber int 
DECLARE @theText varchar 

INSERT INTO @SomeTable (SomeNumber, SomeText) 
SELECT Number, Text 
FROM PrimaryTable 

SET @theCount = 1 
SELECT @theMax = COUNT(ID) FROM @SomeTable 

WHILE (@theCount <= @theMax) 
BEGIN 

    SET @theNumber = 0 
    SET @theText = '' 

    SELECT @theNumber = IsNull(Number, 0), @theText = IsNull(Text, 'nothing') 
    FROM @SomeTable 
    WHERE ID = @theCount 

    -- Do something. 
    PRINT 'This is ' + @theText + ' from record ' + CAST(@theNumber AS varchar) + '.' 

    SET @theCount = @theCount + 1 

END 

PRINT 'Done' 
相關問題