【问题标题】:Optimizing the stored procedure to process 3 million records优化存储过程以处理 300 万条记录
【发布时间】:2010-11-14 10:38:00
【问题描述】:

我在下面设计了一个使用 Sql Server 2005 的存储过程来比较每个 Profile 和 Source 表中的 300 万条记录,并用另一个表 (PROFILE_BC) 中存在的记录更新 Source 表,该表也将有大约 300 万条记录. 我正在尝试优化下面的代码。你能建议任何其他方法吗?我只是担心这需要6个多小时才能完成。我们可以使用 DTS 做同样的事情吗?以及如何使用 DTS 完成此操作的想法。有人建议可以使用一个名为 Lookup,Fuzzy Lookup 的组件。欢迎任何关于优化的想法。

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

【问题讨论】:

    标签: sql sql-server sql-server-2005 tsql


    【解决方案1】:

    如果您考虑性能,则应始终尽量避免使用游标。 您可以这样做,而不是使用光标。在处理 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;
    

    取消注释更新和设置语句并注释掉选择语句进行更新

    【讨论】:

    • 这里的数据类型是 Perm_Disq 是 char(3) 而 voters_no 是 varchar(10)。我想知道 CASE WHEN PROFILE_BC.VOTERS_NO = PERM_DISQ.PERM_DISQ 比较是否正确。您是否还建议在回滚之前将错误处理代码写入日志文件。
    • sry 很难看到您的查询,因为它没有格式化。我将 CASE WHEN PROFILE_BC.VOTERS_NO = PERM_DISQ.PERM_DISQ 更改为 CASE WHEN NOT PROFILE_BC.VOTERS_NO IS NULL 因此,如果在 profile_bc 表中找不到与 voter_no 匹配的记录,则该值将为空
    • 您总是可以将其包装在 try / catch 块中并使用 raiserror 命令引发错误,但我看不出它会在该语句中引发错误的位置,除非您对源表上的PERM_DISQ 列。
    • 我的帖子的主要原因是向您展示您想要的东西可以在不使用游标的情况下实现。当你把它放在存储过程中时,你会想要摆脱 begin trans / rollback trans 语句,除非你将它们包装在 begin trans try .... commit trans catch rollback trans
    猜你喜欢
    • 1970-01-01
    • 2010-10-01
    • 1970-01-01
    • 2011-03-10
    • 1970-01-01
    • 2010-11-24
    • 1970-01-01
    • 1970-01-01
    • 2012-10-21
    相关资源
    最近更新 更多