SQL Server存储过程性能问题-存在

时间:2019-02-23 21:40:22

标签: sql sql-server stored-procedures

我想知道为什么我的存储过程花了这么长时间才让专家们跳出来。

该过程仅在通过某些规则的情况下才尝试在主表中插入/更新事务/记录。

如果失败,它将在另一个表中插入/更新事务/记录。

45,000行的过程大约需要5-8分钟。

它原本可以正常运行,但是需要花费很长时间,而且我知道我的表在几个月后将达到100万条记录,所以我不知道要花多长时间。

我将CTE作为一种选择,但不确定如何使用。

注意:实际上,我发现包括一个临时表要比直接查询该临时表更快。

目标是什么

主要目标是确保插入到最终表中的每个记录都是有效的。

如果一条记录有效,那么它将检查该记录在最终表中是否已经存在;如果存在,它将尝试更新该记录(如果详细信息已更改)。如果尚不存在,则会插入新的。

类似地,如果一条记录无效/错误,则检查该记录是否在另一个非最终表中已经存在;如果存在,它将尝试更新该记录(如果详细信息已更改)。如果它不存在,则插入新的。在此表中包含错误消息。

要成为有效记录

  • 公司ID必须在manager_mapping中
  • 产品ID必须在product_mapping中
  • CCY必须位于dim_ccy
  • 返回必须是数字
  • 起息日必须为日期

注意:验证时发现错误时,我不会立即抛出错误。 @ErrorCode和@ErrorMessage已建立并尽可能具有描述性

SQL代码

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[ETL_stage_evestment_performance_to_champ_2.0]
AS
BEGIN
    SET NOCOUNT ON;

    /*Variable Declaration*/
    DECLARE
        @BatchImportID UNIQUEIDENTIFIER,
        @FileProcessedDate DATETIME,
        @FileProcessedUTCDate DATETIME,
        @ImportStatus TINYINT,
        @ErrorCode VARCHAR(2000),
        @ErrorMessage VARCHAR(4000),
        @StagingID INT,
        @value_date VARCHAR(255),
        @firm_id VARCHAR(255),      
        @product_id VARCHAR(255),
        @vehicle_id VARCHAR(255),
        @ccy VARCHAR(255),
        @reporting_method VARCHAR(255),
        @performance_return VARCHAR(255),
        @log_return VARCHAR(255)

    /*Assign static value for whole one time process*/
    SELECT
        @BatchImportID = NEWID(),
        @FileProcessedDate = GETDATE(),
        @FileProcessedUTCDate = GETUTCDATE()

    /*Create staging table so we can re-run procedure instead of having to rerun complete task again and again*/
    CREATE TABLE #stagingPerformance
    (
            [index] [BIGINT] NULL,
            [value_date] [DATETIME] NULL,                       
            [firm_id] [BIGINT] NULL,
            [ccy] [VARCHAR](MAX) NULL,
            [product_id] [BIGINT] NULL,
            [reporting_method] [VARCHAR](MAX) NULL,
            [vehicle_id] [BIGINT] NULL,
            [performance_return] [FLOAT] NULL,
            [log_return] [FLOAT] NULL
    )

    CREATE INDEX [IX_EvestmentData_1] 
    ON #stagingPerformance ([index] ASC, [value_date] ASC, [firm_id] ASC)

    -- POPULATE TEMP TABLE
    INSERT INTO #stagingPerformance
        SELECT 
            a.[index], a.value_date, a.firm_id, a.ccy, 
            a.product_id, a.reporting_method, a.vehicle_id, 
            a.performance_return, a.log_return
        FROM
            CHAMP_DW.dbo.champ_dw_staging_evestment_performance a

    /*While loop started to get process record one by one*/
    WHILE EXISTS (SELECT 1 FROM #stagingPerformance AS FHD WITH (NOLOCK))
    BEGIN
        BEGIN TRY
            BEGIN TRANSACTION

            /*To assign 1 record values to respective variables*/
            SELECT TOP 1
                @StagingID = FHD.[index],
                @firm_id = NULLIF(FHD.[firm_id],''),
                @product_id = NULLIF(FHD.[product_id],''),
                @vehicle_id = NULLIF(FHD.[vehicle_id],''),
                @value_date = NULLIF(FHD.[value_date],''),
                @reporting_method = NULLIF(FHD.[reporting_method],''),              
                @ccy = NULLIF(FHD.[ccy],''),                
                @performance_return = NULLIF(FHD.[performance_return],''),
                @log_return = NULLIF(FHD.[log_return],'')               
            FROM 
                #stagingPerformance AS FHD WITH (NOLOCK)
            ORDER BY 
                FHD.[index]

            /*Record wise validation start*/
            IF @reporting_method IS NOT NULL 
               AND NOT EXISTS(SELECT 1 WHERE @reporting_method in ('Gross', 'Net', 'Index')) 
            BEGIN
                SELECT
                    @ErrorCode = ISNULL(@ErrorCode,'') + ',' + '115',
                    @ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Reporting Method is invalid'
            END

            IF @value_date IS NOT NULL AND ISDATE(@value_date) = 0 
            BEGIN
                SELECT
                    @ErrorCode = ISNULL(@ErrorCode,'') + ',' + '106',
                    @ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Invalid value of Value Date.'
            END

            IF @performance_return IS NOT NULL  
               AND ISNUMERIC(@performance_return) = 0 
            BEGIN
                SELECT
                    @ErrorCode = ISNULL(@ErrorCode,'') + CASE WHEN @ErrorCode LIKE '%112%' THEN '' ELSE ',' + '112' END,
                    @ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Invalid value of performance.'
            END

            IF @log_return IS NOT NULL AND ISNUMERIC(@log_return) = 0 
            BEGIN
                SELECT
                    @ErrorCode = ISNULL(@ErrorCode,'') + CASE WHEN @ErrorCode LIKE '%112%' THEN '' ELSE ',' + '112' END,
                    @ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Invalid value of log_return.'
            END

            IF @firm_id IS NOT NULL 
               AND NOT EXISTS(SELECT 1 
                              FROM CHAMP_DW.dbo.champ_dw_fund_manager_mapping AS DFM WITH (NOLOCK) 
                              WHERE DFM.evestment_fund_manager_id = @firm_id)
            BEGIN
                SELECT
                    @ErrorCode = ISNULL(@ErrorCode,'') + ',' + '113',
                    @ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Firm ID not Mapped'
            END

            IF @product_id IS NOT NULL AND NOT EXISTS(SELECT 1 FROM dbo.champ_dw_product_mapping AS DAM WITH (NOLOCK) WHERE DAM.evestment_product_id=@product_id)
            BEGIN
                SELECT
                    @ErrorCode = ISNULL(@ErrorCode,'') + ',' + '114',
                    @ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Product ID is not Mapped'
            END

            IF @ccy IS NOT NULL AND NOT EXISTS(SELECT 1 FROM [dbo].champ_dw_dim_currency AS DC WITH (NOLOCK) WHERE DC.currency = @ccy) BEGIN
                SELECT
                    @ErrorCode = ISNULL(@ErrorCode,'') + ',' + '112',
                    @ErrorMessage = ISNULL(@ErrorMessage,'') + ',' + 'Invalid CCY'
            END

            SELECT
                @ErrorCode = NULLIF(STUFF(@ErrorCode,1,1,''),''),
                @ErrorMessage = NULLIF(STUFF(@ErrorMessage,1,1,''),'')

            IF @ErrorMessage IS NOT NULL
            BEGIN
                ;THROW 50552,'VALIDATION RAISE ERROR.',1
            END

            /*Record wise validation end*/

            /*To get unique record value based on columns*/

            DECLARE
                @performance_id bigint = 0,
                @vfirm_id INT,
                @vproduct_id INT,
                @vvehicle_id INT,
                @vvalue_date datetime2,
                @vreporting_method nvarchar(max),
                @vccy nvarchar(3),
                @vperformance_return float,
                @vlog_return float,             
                @map_firm_id INT,
                @map_product_id INT

            SELECT
                @vfirm_id = TRY_PARSE(@firm_id AS INT),
                @vproduct_id = TRY_PARSE(@product_id AS INT),
                @vvehicle_id = TRY_PARSE(@vehicle_id AS INT),
                @vvalue_date = TRY_PARSE(@value_date AS datetime2),
                @vreporting_method = @reporting_method,
                @vccy = cast(@ccy as nvarchar(3)),
                @vperformance_return = TRY_PARSE(@performance_return AS float),
                @vlog_return = TRY_PARSE(@log_return AS float)

            SELECT 
                @map_firm_id = (SELECT fund_manager_mapping_id FROM CHAMP_DW.dbo.champ_dw_fund_manager_mapping fm WHERE fm.evestment_fund_manager_id = @vfirm_id),
                @map_product_id = (SELECT product_mapping_id FROM CHAMP_DW.dbo.champ_dw_product_mapping fp  WHERE fp.product_mapping_id=@vvehicle_id)

            SELECT 
                @performance_id = FFHD.performance_id 
            FROM dbo.[champ_dw_fact_performance] AS FFHD WITH (NOLOCK)
            WHERE FFHD.fund_manager_id = @map_firm_id
                AND FFHD.product_id = @map_product_id
                AND FFHD.value_date = @vvalue_date
                AND FFHD.data_source = 'eVestment'
                AND FFHD.ccy_id = @vccy
                AND FFHD.reporting_method = @vreporting_method

                IF @performance_id IS NOT NULL or @performance_id = 0
                    BEGIN
                        /*Update record, if any value has different then already exist in DB.*/
                        UPDATE FFHD
                        SET 
                            FFHD.ccy_id = @ccy,
                            FFHD.performance_return = @vperformance_return,
                            FFHD.log_return = @vlog_return          
                        FROM dbo.[champ_dw_fact_performance] AS FFHD WITH (NOLOCK)
                        WHERE FFHD.performance_id = @performance_id
                        AND
                        (
                            ISNULL(FFHD.performance_return,'0') <> @vperformance_return
                            OR
                            ISNULL(FFHD.log_return,'0') <> @vlog_return
                        )
                    END
                ELSE
                    BEGIN
                        /*Add new record */         
                        INSERT INTO dbo.[champ_dw_fact_performance]
                        (
                            value_date,
                            reporting_method,
                            valuation_quality,
                            data_source,
                            performance_return,
                            log_return,
                            ccy_id,
                            fund_manager_id,
                            product_id              
                        )
                        SELECT
                            @vvalue_date AS value_date,
                            @vreporting_method AS reporting_method,
                            'Actual' as valuation_quality,
                            'eVestment' as data_source,
                            @vperformance_return AS performance_return,
                            @vlog_return AS log_return,
                            @vccy AS ccy_id,
                            @map_firm_id AS fund_manager_id_id,
                            @map_product_id AS product_id_id
                    END

        COMMIT TRANSACTION  

        END TRY
        BEGIN CATCH

            IF @@TRANCOUNT > 0 
            BEGIN
                ROLLBACK TRANSACTION
            END

            BEGIN TRANSACTION

                DECLARE
                    @ERROR_MESSAGE NVARCHAR(4000)
                SELECT
                    @ERROR_MESSAGE = ERROR_MESSAGE()

                IF @ERROR_MESSAGE <> 'VALIDATION RAISE ERROR.'
                BEGIN
                    SELECT
                        @ErrorCode = ISNULL(@ErrorCode,'') + CASE WHEN ISNULL(@ERROR_MESSAGE,'') <> '' THEN ',' + '999' ELSE '' END,
                        @ErrorMessage = ISNULL(@ErrorMessage,'') + CASE WHEN ISNULL(@ERROR_MESSAGE,'') <> '' THEN ',' + CONVERT(VARCHAR(4000),@ERROR_MESSAGE) ELSE '' END
                END

                SELECT
                    @ErrorCode = NULLIF(CASE WHEN @ErrorCode LIKE '%999%' THEN STUFF(@ErrorCode,1,1,'') ELSE @ErrorCode END,''),
                    @ErrorMessage = NULLIF(CASE WHEN @ErrorCode LIKE '%999%' THEN STUFF(@ErrorMessage,1,1,'') ELSE @ErrorMessage END,'')

                /*To add failed record to table*/

            SELECT 
                @performance_id = FFHD.AutoLogID
            FROM dbo.champ_dw_evestment_performance AS FFHD WITH (NOLOCK)
            WHERE FFHD.firm_id = @vfirm_id
                AND FFHD.product_id = @vproduct_id
                AND FFHD.vehicle_id = @vvehicle_id
                AND FFHD.value_date = @vvalue_date
                AND FFHD.ccy_id = @vccy
                AND FFHD.reporting_method = @vreporting_method

                IF @performance_id IS NOT NULL or @performance_id = 0
                    BEGIN
                        /*Update failed record, if any value has different then already exist in DB.*/
                        UPDATE FFHD
                        SET 
                            FFHD.performance_return = @vperformance_return,
                            FFHD.log_return = @vlog_return,
                            FFHD.BatchImportID = @BatchImportID,
                            FFHD.FileProcessedDate = @FileProcessedDate,
                            FFHD.FileProcessedUTCDate = @FileProcessedUTCDate,
                            FFHD.ErrorCode = @ErrorCode,
                            FFHD.ErrorMessage = @ErrorMessage   
                        FROM dbo.champ_dw_evestment_performance AS FFHD WITH (NOLOCK)
                        WHERE FFHD.AutoLogID = @performance_id
                        AND
                        (
                            ISNULL(FFHD.performance_return,'0') <> @vperformance_return
                            OR
                            ISNULL(FFHD.log_return,'0') <> @vlog_return
                        )
                    END
                ELSE
                    BEGIN
                        /*Add new record */         
                        INSERT INTO dbo.champ_dw_evestment_performance
                        (
                            BatchImportID,
                            FileProcessedDate,
                            FileProcessedUTCDate,
                            ImportStatus,
                            ErrorCode,
                            ErrorMessage,
                            value_date,
                            reporting_method,
                            ccy_id,
                            performance_return,
                            log_return,
                            firm_id,
                            product_id,
                            vehicle_id
                        )
                        SELECT
                            @BatchImportID AS BatchImportID,
                            @FileProcessedDate AS FileProcessedDate,
                            @FileProcessedUTCDate AS FileProcessedUTCDate,
                            0 AS ImportStatus,
                            @ErrorCode AS ErrorCode,
                            @ErrorMessage AS ErrorMessage,
                            @value_date AS value_date,
                            @reporting_method AS reporting_method,
                            @ccy AS ccy_id,
                            @performance_return AS performance_return,
                            @log_return AS log_return,
                            @firm_id AS firm_id,
                            @product_id AS product_id,
                            @vehicle_id AS vehicle_id
                    END

            COMMIT TRANSACTION

        END CATCH;

        DELETE FHD
        FROM #stagingPerformance AS FHD
        WHERE FHD.[index] = @StagingID

        SELECT
            @performance_id = NULL,
            @StagingID = NULL,
            @firm_id = NULL,
            @product_id = NULL,
            @vehicle_id = NULL,
            @value_date = NULL,
            @reporting_method = NULL,
            @ccy = NULL,
            @performance_return = NULL,
            @log_return = NULL,
            @ImportStatus = NULL,
            @ErrorCode = NULL,
            @ErrorMessage = NULL
    END

    SELECT @BatchImportID as 'BatchID'

    DROP TABLE #stagingPerformance  

END

更新工作解决方案-从20分钟下调6秒

    ALTER PROCEDURE [dbo].[ETL_stage_evestment_performance_to_champ_2.0_New]
    AS
    BEGIN
    SET NOCOUNT ON;
            DECLARE
            @BatchImportID UNIQUEIDENTIFIER,
            @FileProcessedDate DATETIME,
            @FileProcessedUTCDate DATETIME,
            @ImportStatus TINYINT,
            @ErrorCode VARCHAR(2000),
            @ErrorMessage VARCHAR(4000),
            @StagingID INT,
            @value_date VARCHAR(255),
            @firm_id VARCHAR(255),      
            @product_id VARCHAR(255),
            @vehicle_id VARCHAR(255),
            @ccy VARCHAR(255),
            @reporting_method VARCHAR(255),
            @performance_return VARCHAR(255),
            @log_return VARCHAR(255)

        /*Assign static value for whole one time process*/
        SELECT
            @BatchImportID = NEWID(),
            @FileProcessedDate = GETDATE(),
            @FileProcessedUTCDate = GETUTCDATE()

        /*Create staging table so we can re-run procedure instead of having to rerun complete task again and again*/

        DECLARE @stagingPerformance TABLE (
                [index] [BIGINT] NULL,
                [value_date] [DATETIME] NULL,                       
                [firm_id] [BIGINT] NULL,
                [ccy] [VARCHAR](MAX) NULL,
                [product_id] [BIGINT] NULL,
                [reporting_method] [VARCHAR](MAX) NULL,
                [vehicle_id] [BIGINT] NULL,
                [performance_return] [FLOAT] NULL,
                [log_return] [FLOAT] NULL,
                [ErrorCode] NVARCHAR(MAX),
                [ErrorMessage] NVARCHAR(MAX)
            )

        -- POPULATE 1st Staging Table with Data and Error Codes and Error Messages
        INSERT INTO @stagingPerformance
            SELECT 
                a.[index],
                NULLIF(a.value_date,''),
                NULLIF(a.firm_id,''),
                NULLIF(a.ccy,''), 
                NULLIF(a.product_id,''),
                NULLIF(a.reporting_method,''), 
                NULLIF(a.vehicle_id,''), 
                NULLIF(a.performance_return,''),
                NULLIF(a.log_return,''),
                '' as ErrorCode,
                '' as ErrorMessage
            FROM
                CHAMP_DW.dbo.champ_dw_staging_evestment_performance a


            /* Have one update, but set one variable concatenated
                or alternatively change the below to have multiple updates per condition and then you are able to set multiple variables per condition*/
            UPDATE @stagingPerformance

                SET ErrorCode = 
                    CASE WHEN reporting_method IS NOT NULL AND reporting_method IN ('Gross', 'Net', 'Index')
                    THEN ''
                    ELSE ','+'115'
                    END
                    +
                    CASE WHEN value_date IS NOT NULL AND ISDATE(value_date) = 1 
                    THEN ''
                    ELSE ','+'106'
                    END
                    +
                    CASE WHEN firm_id IS NOT NULL AND DFM.evestment_fund_manager_id IS NOT NULL 
                    THEN ''
                    ELSE ','+'113' 
                    END 
                    +
                    CASE WHEN product_id IS NOT NULL AND DAM.evestment_product_id IS NOT NULL 
                    THEN ''
                    ELSE ','+'114'
                    END
                    +                               
                    CASE WHEN ccy IS NOT NULL AND DC.currency IS NOT NULL 
                    THEN ''
                    ELSE ','+'112' 
                    END

                ,ErrorMessage= 
                    CASE WHEN reporting_method IS NOT NULL AND  reporting_method IN ('Gross', 'Net', 'Index')
                    THEN ''
                    ELSE ','+'Invalid Reporting Method'--115 
                    END
                    +
                    CASE WHEN value_date IS NOT NULL AND ISDATE(value_date) = 1 
                    THEN ''
                    ELSE ','+'Invalid Value Date'--106
                    END
                    +
                    CASE WHEN firm_id IS NOT NULL AND DFM.evestment_fund_manager_id IS NOT NULL 
                    THEN ''
                    ELSE ','+'Unmapped Firm' --113
                    END 
                    +
                    CASE WHEN product_id IS NOT NULL AND DAM.evestment_product_id IS NOT NULL 
                    THEN ''
                    ELSE ','+'Unmapped Product' --114
                    END
                    +                               
                    CASE WHEN ccy IS NOT NULL AND DC.currency IS NOT NULL 
                    THEN ''
                    ELSE ','+'Invalid CCY' --112
                    END

            FROM
                @stagingPerformance a 
                LEFT JOIN CHAMP_DW.dbo.champ_dw_fund_manager_mapping AS DFM ON DFM.evestment_fund_manager_id = a.firm_id
                LEFT JOIN CHAMP_DW.dbo.champ_dw_product_mapping DAM ON DAM.evestment_product_id = a.product_id
                LEFT JOIN CHAMP_DW.dbo.champ_dw_dim_currency AS DC WITH (NOLOCK) ON DC.currency = a.ccy


            /* Remove leading "," */
            UPDATE @stagingPerformance
            SET ErrorCode = STUFF(ErrorCode,1,1,'')
            WHERE ErrorCode LIKE ',%'

            UPDATE @stagingPerformance
            SET ErrorMessage= STUFF(ErrorMessage,1,1,'')
            WHERE ErrorMessage LIKE ',%'

    --------------------------------------------------------------------------------------------------------------------
    /* RECORD HANDLING (Records without validation errors) */
    --------------------------------------------------------------------------------------------------------------------
            DECLARE @stagingPerformanceNoError TABLE (
                    do_create bit,
                    performance_id BIGINT,
                    vfirm_id BIGINT NULL,
                    vproduct_id BIGINT,
                    vvehicle_id BIGINT,
                    vvalue_date datetime2,
                    vreporting_method nvarchar(max),
                    vccy nvarchar(3),
                    vperformance_return float,
                    vlog_return float,             
                    map_firm_id INT,
                    map_product_id INT

            )

            /* Move from Staging Table 1 to Staging Table 2 all records without errors */
            INSERT INTO  @stagingPerformanceNoError              

                    SELECT 

                    CASE WHEN FFHD.performance_id  IS NOT NULL AND 
                    (
                        ISNULL(FFHD.performance_return,'0') <> a.performance_return
                        OR
                        ISNULL(FFHD.log_return,'0') <> a.log_return
                    )
                    THEN 0 ELSE 1 END AS do_create,--create 1=update 0 /*Same Criteria as before to decide when to Insert or when to Update */
                    FFHD.performance_id  as performance_id,
                    a.firm_id,
                    a.product_id,
                    a.vehicle_id,
                    a.value_date,
                    a.reporting_method,
                    a.ccy, --char 3
                    a.performance_return,
                    a.log_return,
                    fm.fund_manager_mapping_id as map_firm_id,--map_firm_id
                    fp.product_mapping_id as map_product_id--map_product_id

            FROM @stagingPerformance a 
            LEFT JOIN CHAMP_DW.dbo.champ_dw_fund_manager_mapping fm ON fm.evestment_fund_manager_id = a.firm_id 
            LEFT JOIN CHAMP_DW.dbo.champ_dw_product_mapping fp  ON fp.product_mapping_id=a.vehicle_id
            LEFT JOIN  CHAMP_DW.dbo.[champ_dw_fact_performance] AS FFHD
                ON FFHD.fund_manager_id = fm.fund_manager_mapping_id
                    AND FFHD.product_id = fp.product_mapping_id
                    AND FFHD.value_date = a.value_date
                    AND FFHD.data_source = 'eVestment'
                    AND FFHD.ccy_id = ccy
                    AND FFHD.reporting_method = a.reporting_method
            WHERE a.ErrorCode='' /* Only records without errors are moved to staging table 2*/


            /*Update record, if any value has different then already exist in DB.*/
            UPDATE CHAMP_DW.dbo.[champ_dw_fact_performance]
            SET 
                ccy_id = a.vccy,
                performance_return = a.vperformance_return,
                log_return = a.vlog_return          
            FROM dbo.[champ_dw_fact_performance] AS FFHD WITH (NOLOCK)
            INNER JOIN @stagingPerformanceNoError a ON a.performance_id=FFHD.performance_id 
            WHERE do_create=0 /*Update*/

            /*Add new record */         
            INSERT INTO dbo.[champ_dw_fact_performance]
            (
                value_date,
                reporting_method,
                valuation_quality,
                data_source,
                performance_return,
                log_return,
                ccy_id,
                fund_manager_id,
                product_id              
            )
            SELECT
                vvalue_date AS value_date,
                vreporting_method AS reporting_method,
                'Actual' as valuation_quality,
                'eVestment' as data_source,
                vperformance_return AS performance_return,
                vlog_return AS log_return,
                vccy AS ccy_id,
                map_firm_id AS fund_manager_id_id,
                map_product_id AS product_id_id
            FROM @stagingPerformanceNoError
            WHERE do_create=1 /*Insert*/
            AND performance_id  IS  NULL



    --------------------------------------------------------------------------------------------------------------------
    /* ERROR HANDLING - Records with Validation ERRORS */
    --------------------------------------------------------------------------------------------------------------------



        DECLARE @stagingPerformanceError TABLE (
                [performance_id] [BIGINT] NULL,
                [index] [BIGINT] NULL,
                [value_date] [DATETIME] NULL,                       
                [firm_id] [BIGINT] NULL,
                [ccy] [VARCHAR](MAX) NULL,
                [product_id] [BIGINT] NULL,
                [reporting_method] [VARCHAR](MAX) NULL,
                [vehicle_id] [BIGINT] NULL,
                [performance_return] [FLOAT] NULL,
                [log_return] [FLOAT] NULL,
                [ErrorCode] NVARCHAR(MAX),
                [ErrorMessage] NVARCHAR(MAX)
            )


        -- POPULATE Error Table
        INSERT INTO @stagingPerformanceError
            SELECT 
                NULL, --performance_id
                a.[index],
                NULLIF(a.value_date,''),
                NULLIF(a.firm_id,''),
                NULLIF(a.ccy,''), 
                NULLIF(a.product_id,''),
                NULLIF(a.reporting_method,''), 
                NULLIF(a.vehicle_id,''), 
                NULLIF(a.performance_return,''),
                NULLIF(a.log_return,''),
                NULLIF(a.ErrorCode,''),
                NULLIF(a.ErrorMessage,'')
            FROM
                @stagingPerformance a
            WHERE a.ErrorCode<>''


            UPDATE @stagingPerformanceError
                SET performance_id= FFHD.AutoLogID
                FROM @stagingPerformanceError a 
                INNER JOIN dbo.champ_dw_evestment_performance AS FFHD 
                ON FFHD.firm_id = a.firm_id
                    AND FFHD.product_id = a.product_id
                    AND FFHD.vehicle_id = a.vehicle_id
                    AND FFHD.value_date = a.value_date
                    AND FFHD.ccy_id = a.ccy
                    AND FFHD.reporting_method = a.reporting_method


                /*Update failed record, if any value has different then already exist in DB.*/
                UPDATE FFHD
                SET 
                    FFHD.performance_return = a.performance_return,
                    FFHD.log_return = a.log_return,
                    FFHD.BatchImportID = @BatchImportID,
                    FFHD.FileProcessedDate = @FileProcessedDate,
                    FFHD.FileProcessedUTCDate = @FileProcessedUTCDate,
                    FFHD.ErrorCode = @ErrorCode,
                    FFHD.ErrorMessage = @ErrorMessage   
                FROM dbo.champ_dw_evestment_performance AS FFHD
                INNER JOIN @stagingPerformanceError a ON FFHD.AutoLogID = a.performance_id
                WHERE FFHD.AutoLogID = a.performance_id
                AND
                (
                    ISNULL(FFHD.performance_return,'0') <> a.performance_return
                    OR
                    ISNULL(FFHD.log_return,'0') <> a.log_return
                )
                AND a.performance_id IS NOT NULL


                /*Add new record */         
                INSERT INTO dbo.champ_dw_evestment_performance
                (
                    BatchImportID,
                    FileProcessedDate,
                    FileProcessedUTCDate,
                    ImportStatus,
                    ErrorCode,
                    ErrorMessage,
                    value_date,
                    reporting_method,
                    ccy_id,
                    performance_return,
                    log_return,
                    firm_id,
                    product_id,
                    vehicle_id
                )
                SELECT
                    @BatchImportID AS BatchImportID,
                    @FileProcessedDate AS FileProcessedDate,
                    @FileProcessedUTCDate AS FileProcessedUTCDate,
                    0 AS ImportStatus,
                    A.ErrorCode AS ErrorCode,
                    a.ErrorMessage AS ErrorMessage,
                    a.value_date AS value_date,
                    a.reporting_method AS reporting_method,
                    a.ccy AS ccy_id,
                    a.performance_return AS performance_return,
                    a.log_return AS log_return,
                    a.firm_id AS firm_id,
                    a.product_id AS product_id,
                    a.vehicle_id AS vehicle_id

                FROM @stagingPerformanceError a
                WHERE a.performance_id IS  NULL
    END

1 个答案:

答案 0 :(得分:4)

以下是一些使用基于集合的操作而不是RBAR的示例。这些只是一口气完成了整个操作,而不是慢慢地循环。

由于您的proc的复杂性,我可能错过了一些东西,但这给了您一个主意

第一个很简单-只需根据where子句更新一条记录

  update dbo.champ_dw_evestment_performance
  set ErrorMessage  =  ISNULL(ErrorMessage,'') + 'Reporting Method is invalid'
  where reporting_method NOT IN ('Gross', 'Net', 'Index')
  and reporting_method IS NOT NULL

这一次标记了所有记录 而不是慢慢地循环

第二个示例是再次更新的示例,其中带有一个where,但是该示例在存在内部具有“关联”联接

  update TGT
  set ErrorMessage  =  ISNULL(ErrorMessage,'') + 'Firm ID not Mapped'
  FROM dbo.champ_dw_evestment_performance AS TGT
  WHERE NOT EXISTS (
      SELECT * FROM CHAMP_DW.dbo.champ_dw_fund_manager_mapping AS DFM
      WHERE DFM.evestment_fund_manager_id = TGT.firm_id
  )

您应该能够使用这两个概念从循环中删除很多这些更新。

关于dbo.[champ_dw_fact_performance]的更新。.我不能跟随您在这里所做的事情,但是我敢肯定,即使其中有一些加入,您也可以在一条语句中做到这一点。它。

我认为我没有在您的代码中看到任何联接。您真的需要了解这些。

因此,如果这对您有意义,并且您希望我攻击champ_dw_fact_performance更新,请告诉我。解开它有点费力