2010-11-14 9 views
2

J'ai conçu une procédure stockée usign Sql Server 2005 ci-dessous pour comparer 3 millions d'enregistrements dans les tables Profile et Source, et mettre à jour la table Source avec les enregistrements existants dans une autre table (PROFILE_BC) qui aura également environ 3 millions de dossiers. J'essaie d'optimiser ce code ci-dessous. Pouvez-vous suggérer une autre méthode? Je m'inquiétais juste que cela prendra plus de 6 heures à compléter. Pouvons-nous faire la même chose en utilisant DTS? Et des idées comment cela peut être fait en utilisant DTS. Certains ont suggéré qu'il existe un composant appelé, Lookup, Fuzzy Lookup qui peut être utilisé. Toutes les idées pour optimiser le même sont les bienvenues.Optimisation de la procédure stockée pour traiter 3 millions d'enregistrements

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 

Répondre

2

Vous devriez toujours essayer d'éviter d'utiliser des curseurs si vous avez des performances à l'esprit. Au lieu d'utiliser un curseur, vous pouvez le faire. Essayez de penser en termes d'ensembles en traitant avec SQL. J'ai commenté la partie mise à jour de la requête et ajouté un select afin que vous puissiez voir les données.

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; 

uncomment la mise à jour et instruction set et commentez l'instruction select mettre à jour

+0

Les types de données ici sont Perm_Disq est un char (3) et voters_no est un varchar (10). Je me demandais si la comparaison CASE WHEN PROFILE_BC.VOTERS_NO = PERM_DISQ.PERM_DISQ est correcte. Suggéreriez-vous également un code de gestion des erreurs à écrire dans un fichier journal avant la restauration. – Ruruboy

+0

Il était difficile de voir votre requête car elle n'était pas formatée. J'ai changé CAS LORSQUE PROFILE_BC.VOTERS_NO = PERM_DISQ.PERM_DISQ à CAS LORSQUE NOT PROFILE_BC.VOTERS_NO EST NULL, donc s'il ne pouvait pas trouver un enregistrement qui correspondait à l'électeur_no dans la table profile_bc, cette valeur serait null – clyc

+0

, vous pourriez toujours envelopper dans un bloc try/catch et déclenche une erreur avec la commande raiserror, mais je ne vois pas où cela déclencherait une erreur dans cette instruction, sauf si vous avez une contrainte sur la colonne PERM_DISQ de la table Source. – clyc