2013-06-26 174 views
0

昨天我注意到了一個非常有趣的(也是意想不到的)事情。我得到了一個任務(在生產環境中),通過獲取dummytable中的所有值來更新TableA的三列(由於某些顯而易見的原因,我正在更改表和列的名稱)。這兩個表的主鍵都是A列。我知道這個任務非常簡單,可以通過多種方式完成,但我選擇編寫一個存儲過程(如下所示)。MySql過程產生錯誤結果

當存儲過程完成執行時,注意到列B,C & statusCode具有相同的值(即,成千上萬條記錄在這三列中具有相同的值)。有人能告訴我哪裏出了問題嗎?

1)這個存儲過程有什麼問題(或缺失)? (Dummy table也有成千上萬的記錄) 2)除了創建存儲過程之外,完成此任務的最佳方式是什麼?

PS:我在使用MySQL工作臺的生產環境中創建(執行了這個存儲過程),並且在過程的執行過程中出現了一個異常:「與MySQL服務器失去連接」,但我猜想自從我運行在遠程計算機上執行此過程時,在執行過程時服務器上沒有中斷。

這是我的存儲過程。

DELIMITER $$ 

CREATE DEFINER=`ABC`@`%` PROCEDURE `RetrieveExtractionData`() 

BEGIN 

DECLARE claimlisttraversed BOOLEAN DEFAULT FALSE; 

DECLARE a VARCHAR(20); 

DECLARE b INTEGER; 

DECLARE c INTEGER; 


DECLARE claimlist CURSOR FOR SELECT 
`dummytable`.`A`, 
`dummytable`.`B`, 
`dummytable`.`C` 
FROM `ABC`.`dummytable`; 

DECLARE CONTINUE HANDLER FOR NOT FOUND SET claimlisttraversed = TRUE; 


OPEN claimlist; 

claimlistloop: LOOP 

    FETCH claimlist INTO a, b, c; 

    IF claimlisttraversed THEN 
     CLOSE claimlist; 
     LEAVE claimlistloop; 
    END IF; 
    UPDATE `ABC`.`TableA` 
SET 
`B` = b, 
`C` = c, 
`statuscode` = 'Sent' 
WHERE `A` = a; 

END LOOP claimlistloop; 

END 

回答

1

關於第一個問題:

1)什麼是錯的,或者沒有在這個存儲過程? (虛表有 成千上萬的記錄以及)

我想你忘了CLOSECURSOR。在您結束LOOP之後,您應該CLOSECURSOR

END LOOP claimlistloop; 

CLOSE claimlist; 

END 

2)什麼能完成這個任務比其他 創建存儲過程的最佳方法是什麼?

這樣做在STORED PROCEDURE應該沒問題。而且使用CURSOR會很好,因爲您只需執行一次程序(我猜是因爲這是一個生產修復程序)。

但是從您的問題來看,您只是想根據提供的DummyTable更新TableA。我假設這些表具有相同的列。

所以我覺得這個查詢比CURSOR更好:

UPDATE TableA A 
    INNER JOIN DummyTable D ON D.A = A.A 
    SET A.B = D.B 
     , A.C = D.C 
     , A.statuscode = 'Sent'; 

但請先嚐試在備份或虛擬表。我還沒有測試過。

1

忘記光標。事實上,如果可以避免的話,你永遠不應該使用遊標。遊標非常慢。

根本就

UPDATE 
yourTable yt 
INNER JOIN dummyTable dt ON yt.A = dt.A 
SET 
yt.B = dt.B, 
yt.C = dt.C; 

和你的罰款。

+0

感謝您的回覆,但您能否解釋爲什麼在這個特殊情況下光標會變慢? –

+0

不僅在這個特殊的例子中,它們總是**緩慢。解釋爲什麼會過深入源代碼。但光標首先會讀取整個虛擬表格並將其保存在內存中。然後逐行執行更新語句。而使用簡單的更新語句讀取兩個表的部分內容,並將一些指向內存地址的指針交換並寫回到磁盤。非常快。 – fancyPants

1

1)這個存儲過程有什麼問題(或缺失)? (虛擬表 也有數千條記錄)
2)除了創建存儲過程之外,可能最好的 執行此任務的方式是什麼?

恕我直言,你目前失蹤的最重要的事情是,你不需要任何遊標。您的整個存儲過程是一個UPDATE聲明。單獨執行,或在存儲過程中

CREATE PROCEDURE RetrieveExtractionData() 
UPDATE TableA a JOIN dummytable d 
    ON a.a = d.a 
    SET a.b = d.b, a.c = d.c, a.statuscode = 'Sent'; 

你甚至都不需要改變一個分隔符,使用BEGIN ... END

這裏是SQLFiddle演示包裹。

+0

不錯。謝謝peterm。 :) 由於KaeL首先回答了問題,因此表示接受了他的回答。 –