【问题标题】:How can I write better SQL statement for data validation如何编写更好的 SQL 语句进行数据验证
【发布时间】:2021-07-31 04:29:17
【问题描述】:

我正在编写一个存储过程。在其中,我有使用 if 条件的数据验证。例如,如果第一个条件是成功,我将调用存储过程。如果 if 条件失败,我将调用另一个存储过程。同样,我有 20 多个条件可以在一个存储过程中运行。这会产生性能问题。对于以下场景,我该如何以更好的方式编写。

CREATE PROCEDURE Sample 
    <@Param1, sysname, @p1> <Datatype_For_Param1, , int> = <Default_Value_For_Param1, , 0>, 
    <@Param2, sysname, @p2> <Datatype_For_Param2, , int> = <Default_Value_For_Param2, , 0>
AS
BEGIN
    IF @ModeClass = 'I'
    BEGIN 
        --Validation 001
        IF EXISTS (SELECT rderNumber FROM OrderHeader WHERE OrderNumber = @OrderNumber) 
            SET @STATE_H001 = 0;
            SET @FatalCode ='H001';
            SET @FatalFlag = 'F';
            EXEC spLinkTrackOrderProcessingResult 
                                                @pross, @RunningID, @BatchNumber, @FatalFlag, @RecordType, @OrderNumber,
                                                @Sequence1, @Sequence2, @CustomerCode, @Customerabbreviation, @LoadPlanNumber, @InvoiceNumber,
                                                @JobPlaningNumber,  @CompanyCode,   @PlantAbbreviation, @ModeClass,             @FieldName,         @BeforeChangeValue,
                                                @AfterChangeValue,  @FatalCode,     @FatalMessage,      @HeaderErrorFlag,       @DetailErrorFlag,   @ProcessUser,
                                                @ProcessDate,       @SolvedUser,    @SolvedDate,        @CreateUser,            @CreateDate,        @ChangeUser, 
                                                @ChangeDate,        @ByProgram,     @ByMachine;
        ELSE
            BEGIN
                SET @STATE_H001 = 1;
            END

        --Validation 002
        IF EXISTS (SELECT top 1 1  FROM OrderDetail WHERE OrderNumber = @OrderNumber) 
            BEGIN
                SET @STATE_H004 = 1;
            END
        ELSE
            BEGIN
                SET @STATE_H004 = 0;
                SET @FatalCode ='H004';
                SET @FatalFlag = 'F';
                EXEC spLinkTrackOrderProcessingResult 
                                                    @pross,             @RunningID,     @BatchNumber,       @FatalFlag,             @RecordType,        @OrderNumber,
                                                    @Sequence1,         @Sequence2,     @CustomerCode,      @Customerabbreviation,  @LoadPlanNumber,    @InvoiceNumber,
                                                    @JobPlaningNumber,  @CompanyCode,   @PlantAbbreviation, @ModeClass,             @FieldName,         @BeforeChangeValue,
                                                    @AfterChangeValue,  @FatalCode,     @FatalMessage,      @HeaderErrorFlag,       @DetailErrorFlag,   @ProcessUser,
                                                    @ProcessDate,       @SolvedUser,    @SolvedDate,        @CreateUser,            @CreateDate,        @ChangeUser, 
                                                    @ChangeDate,        @ByProgram,     @ByMachine;
            END
      END 
END
GO

【问题讨论】:

  • 基于集合的验证方法是编写一个一次性验证多个条件的查询。
  • 忽略不完整和无效的sql,定义“更好”。 IMO 这种方法非常不寻常,但没有人知道您到底想要完成什么(注意 what,而不是 如何)。此外,除了您之外,没有人知道您的“性能条件”是什么意思。但我猜你以 RBAR 方式使用验证逻辑(作为 ETL 过程的一部分),这就是你的性能问题的根源。
  • 如果你需要为每个条件运行一个存储过程,那么你会有很大的性能问题。可能有一种更全面的方法,根本不使用存储过程。这只是一个建议,因为您的问题没有足够的信息来说明更多信息。

标签: sql sql-server tsql query-optimization


【解决方案1】:

性能问题是因为您的执行计划很复杂。重新组织您的验证,仅使用您的验证结果调用记录器 SP 一次,并且不要使用 else 子句。

基于您的代码的示例:

CREATE PROCEDURE Sample 
    <@Param1, sysname, @p1> <Datatype_For_Param1, , int> = <Default_Value_For_Param1, , 0>, 
    <@Param2, sysname, @p2> <Datatype_For_Param2, , int> = <Default_Value_For_Param2, , 0>
AS
BEGIN
    IF @ModeClass = 'I'
    BEGIN 
        SET @STATE_H001 = 1;
        SET @STATE_H004 = 1;
        --Validation 001
        IF EXISTS (SELECT rderNumber FROM OrderHeader WHERE OrderNumber = @OrderNumber) 
        BEGIN
            SET @STATE_H001 = 0;
            SET @FatalCode ='H001';
            SET @FatalFlag = 'F';
        END;

        --Validation 002
        IF @STATE_H001 = 1 and NOT EXISTS (SELECT top 1 1  FROM OrderDetail WHERE OrderNumber = @OrderNumber) 
        BEGIN
                SET @STATE_H004 = 0;
                SET @FatalCode ='H004';
                SET @FatalFlag = 'F';
        END;
    END 
      
    if @STATE_H001 = 0 or @STATE_H004 = 0
        EXEC spLinkTrackOrderProcessingResult 
            @pross, @RunningID, @BatchNumber, @FatalFlag, @RecordType, @OrderNumber,
            @Sequence1, @Sequence2, @CustomerCode, @Customerabbreviation, @LoadPlanNumber, @InvoiceNumber,
            @JobPlaningNumber,  @CompanyCode,   @PlantAbbreviation, @ModeClass,             @FieldName,         @BeforeChangeValue,
            @AfterChangeValue,  @FatalCode,     @FatalMessage,      @HeaderErrorFlag,       @DetailErrorFlag,   @ProcessUser,
            @ProcessDate,       @SolvedUser,    @SolvedDate,        @CreateUser,            @CreateDate,        @ChangeUser, 
            @ChangeDate,        @ByProgram,     @ByMachine;
    
END
GO

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多