2010-11-14 97 views
2

下面我設計了一個存儲過程,用於對比下面的每個Profile和Source Table中的300萬條記錄,並使用另一個表中存在的記錄(PROFILE_BC)更新Source表)也將有約300萬條記錄。 我想優化下面的這段代碼。你能提出任何其他方法嗎?我只是擔心這將需要6個多小時才能完成。我們可以使用DTS來做同樣的事嗎?並想法如何使用DTS來完成。一些人建議有一個叫做Lookup的組件,可以使用模糊查找。歡迎任何優化相同的想法。優化存儲過程以處理300萬條記錄

USE Database 

GO 
/****** Object: StoredProcedure [dbo].[ProcName] Script Date: 11/13/2010 17:15:04 ******/ 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 

CREATE PROCEDURE [dbo].[ProcName] 
AS 
BEGIN 

SET NOCOUNT ON; 

DECLARE @not_on_ebc_file_xx## char(2); 
    SET @not_on_ebc_file_xx## = 35; 

DECLARE @voters_no varchar(18); 
    DECLARE @candidate_id char(10); 
DECLARE @perm_disq_temp char(2); 
DECLARE @voters_no_jms varchar(18); 


DECLARE PROFILES_CURSOR CURSOR LOCAL FAST_FORWARD 
    FOR SELECT CP.CANDIDATE_ID, CP.VOTERS_NO FROM PROFILE CP INNER JOIN SOURCE SR ON 
CP.CANDIDATE_ID = SR.CANDIDATE_ID 
WHERE CP.CANDIDATE_ID NOT LIKE 'MA%'; 


OPEN PROFILES_CURSOR; 
FETCH NEXT FROM PROFILES_CURSOR 
INTO @candidate_id, @voters_no; 


    WHILE @@FETCH_STATUS = 0 
    BEGIN 

    SELECT @voters_no_jms = VOTERS_NO FROM PROFILE_BC WHERE VOTERS_NO = @voters_no; 
    SELECT @perm_disq_temp = PERM_DISQ FROM SOURCE WHERE CANDIDATE_ID = @candidate_id; 

    IF (@voters_no_jms = @voters_no) -- record exists in jms_temp table/ebc file 
    BEGIN 
    IF (@perm_disq_temp = @not_on_ebc_file_xx##) 
    BEGIN 
     UPDATE SOURCE SET PERM_DISQ = '' WHERE CANDIDATE_ID = @candidate_id; 
    END 

    END 
    ELSE 
    BEGIN 
    IF (@perm_disq_temp = '' OR @perm_disq_temp IS NULL) 
    BEGIN 
     UPDATE SOURCE SET PERM_DISQ = @not_on_ebc_file_xx## WHERE CANDIDATE_ID = @candidate_id; 
    END 
    END 

    SET @voters_no_jms = ''; 

    FETCH NEXT FROM PROFILES_CURSOR INTO @candidate_id, @voters_no; 

    END 

CLOSE PROFILES_CURSOR; 
DEALLOCATE PROFILES_CURSOR; 

END 

回答

2

如果你有想到的表現,你應該總是儘量避免使用遊標。 而不是使用遊標,你可以做到這一點。嘗試在處理SQL時考慮集合。我註釋了查詢的更新部分並添加了一個選擇,以便您可以查看數據。

BEGIN TRANSACTION 

DECLARE @not_on_ebc_file_xx## char(2); 
SET @not_on_ebc_file_xx## = 35; 

--UPDATE SR 
--SET  PERM_DISQ = 
--   CASE WHEN NOT PROFILE_BC.VOTERS_NO IS NULL THEN 
--     CASE WHEN PERM_DISQ.PERM_DISQ = @not_on_ebc_file_xx## THEN '' 
--      ELSE PERM_DISQ.PERM_DISQ 
--     END 
--    WHEN PERM_DISQ.PERM_DISQ = '' OR PERM_DISQ IS NULL THEN @not_on_ebc_file_xx## 
--    ELSE PERM_DISQ.PERM_DISQ 
--   END 
SELECT CASE WHEN NOT PROFILE_BC.VOTERS_NO IS NULL THEN 
        CASE WHEN PERM_DISQ.PERM_DISQ = @not_on_ebc_file_xx## THEN '' 
         ELSE PERM_DISQ.PERM_DISQ 
        END 
       WHEN PERM_DISQ.PERM_DISQ = '' OR PERM_DISQ IS NULL THEN @not_on_ebc_file_xx## 
       ELSE PERM_DISQ.PERM_DISQ 
      END AS PERM_DISQ 
FROM PROFILE CP 
     INNER JOIN SOURCE SR 
      ON CP.CANDIDATE_ID = SR.CANDID_ID 
     LEFT JOIN PROFILE_BC 
      ON CP.VOTERS_NO = PROFILE_BC.VOTERS_NO 
     LEFT JOIN SOURCE PERM_DISQ 
      ON CP.CANDIDATE_ID = PERM_DISQ.CANDIDATE_ID 
WHERE CP.CANDIDATE_ID NOT LIKE 'MA%'; 


ROLLBACK TRANSACTION; 

取消對更新和設置語句和註釋掉select語句來更新

+0

這裏的數據類型是Perm_Disq是char(3)和voters_no是一個varchar(10)。我想知道是否CASE時PROFILE_BC.VOTERS_NO = PERM_DISQ.PERM_DISQ比較是正確的。你也會建議一個錯誤處理代碼在回滾之前寫入日誌文件。 – Ruruboy 2010-11-14 02:27:31

+0

sry很難看到您的查詢,因爲它沒有格式化。我將CASE當PROFILE_BC.VOTERS_NO = PERM_DISQ.PERM_DISQ更改爲CASE WHEN NOT PROFILE_BC.VOTERS_NO爲NULL,因此如果它找不到與profile_bc表中的voter_no匹配的記錄,則該值將爲空 – clyc 2010-11-14 02:33:21

+0

您可以始終將其包裝一個try/catch塊,並用raiserror命令引發一個錯誤,但是我沒有看到它會在這個語句中產生錯誤,除非你對源表的PERM_DISQ列有一些限制。 – clyc 2010-11-14 02:35:42