【问题标题】:PLSQL Performance issue multiple schemas procedurePLSQL 性能问题多模式过程
【发布时间】:2019-05-29 22:41:17
【问题描述】:

我有两个模式,LDS 和 LDSI。 (Oracle 11.2.0.3.0)

LDSI 是类似于模式的接口,它充当一些基于队列/事件的模式。有一个充当队列列表的表,以及一个调度作业来处理它。 (Create_Splits)

   PROCEDURE create_split_lots IS
        CURSOR splits IS
            SELECT   *
            FROM     ldsi_v_event_changes_base
            WHERE    interface_name = 'LDSI_SPLITS_MERGES'
            AND      (event_type = 'SPLIT_START')
            AND      transfer_state = 'N'
            AND      dml_operation = 'INS'
            ORDER BY event_ts ASC;  --FOR UPDATE NOWAIT

        l_log_id             NUMBER;
        l_lot_id             NUMBER;
        l_dependant_lot_id   NUMBER;
        l_event_date         DATE;
    BEGIN
        FOR lot IN splits LOOP
            BEGIN
                l_lot_id := lds_owner.lds_lot.get_or_create_lot(p_lotid => lot.lotid, p_system_code => lot.system_code);
                l_dependant_lot_id :=
                    lds_owner.lds_lot.get_or_create_lot(p_lotid => lot.dependant_lotid,
                                                        p_system_code => lot.dependant_system_code);

                IF l_lot_id IS NULL OR l_dependant_lot_id IS NULL THEN
                    raise_application_error(-20343,'error ' );
                END IF;

                lds_owner.lds_event.copy_events(p_source_lot_id => l_dependant_lot_id,
                                                p_target_lot_id => l_lot_id,
                                                p_until_date => l_event_date,
                                                p_deep_copy => TRUE);

                ldsi_lot_container_consumer.complete_get_event_change(p_id => lot.id);
                COMMIT;
            EXCEPTION
                WHEN OTHERS THEN
                    ROLLBACK;
                    ldsi_log.log_fatal_error(p_message => 'SQLCODE:' || SQLCODE || ' Message: ' || SQLERRM)                      
                    CONTINUE;
            END;
        END LOOP;
    END;

现在 LDS_OWNER 是包含所有数据、批次信息、事件信息等的模式。 这个调用需要 ALWAYS 一分钟,即使它没有事件 已经在游标中单独测试了查询,那里的性能没有问题。

lds_owner.lds_event.copy_events(p_source_lot_id => l_dependant_lot_id,
                                                p_target_lot_id => l_lot_id,
                                                p_until_date => l_event_date,
                                                p_deep_copy => TRUE);

它位于 LDS_OWNER 模式中。代码逻辑很简单,有一个事件表,包含一个LOT的所有事件,程序将一个LOT的所有事件复制到另一个LOT。

 PROCEDURE copy_events (p_source_lot_id   IN lds_lots.id%TYPE,
                         p_target_lot_id   IN lds_lots.id%TYPE,
                         p_until_date      IN DATE DEFAULT SYSDATE,
                         p_deep_copy       IN BOOLEAN DEFAULT FALSE)
  IS
    l_log_id                     NUMBER;
    l_has_events                 BOOLEAN :=FALSE;

    CURSOR list_of_events (p_source_lot_id IN lds_lots.id%TYPE, p_target_lot_id IN lds_lots.id%TYPE)
    IS
      SELECT *
        FROM (
               SELECT p1.id,
                      p1.evtt_id,
                      p1.state,
                      p1.channel_type,
                      p1.hist_date,
                      p1.hist_seqnum,
                      p1.postponed_ny,
                      p1.postponed_by,
                      p1.postponed_date,
                      p1.target_area,
                      p1.escalated_ny,
                      p1.escalated_to,
                      p1.escalated_by,
                      p1.escalated_date,
                      p1.released_ny,
                      p1.released_by,
                      p1.released_date,
                      p1.created_by,
                      p1.created_date,
                      p1.modified_by,
                      p1.modified_date,
                      p1.lot_id,
                      p1.copy_ny,
                      CAST (p2.dependant_event_type AS VARCHAR2 (30))   AS copy_reason,
                      p1.parent_evt_id,
                      p1.origin_evt_id
                 FROM lds_events  p1
                      JOIN lds_v_event_changes_base p2
                        ON (p1.lot_id = p2.dependant_lotid
                        AND p2.dependant_lotid = p_source_lot_id
                        AND p2.lotid = p_target_lot_id) /*AND P2.EVENT_TYPE = 'SPLIT_START'*/
                WHERE p1.lot_id = p_source_lot_id
                  AND ((p1.origin_evt_id NOT IN (SELECT origin_evt_id
                                                   FROM lds_events
                                                  WHERE lds_events.lot_id = p_target_lot_id)
                     OR p1.origin_evt_id IS NULL)
                   AND NOT EXISTS
                         (SELECT 1
                            FROM lds_owner.lds_events
                           WHERE lds_owner.lds_events.lot_id = p_target_lot_id
                             AND p1.id = origin_evt_id))
                  AND p1.created_date < COALESCE (NULL, SYSDATE)
                  AND p1.state = 'OPEN'
                  AND p1.created_date < p2.event_ts
             );

    l_temp_event                 lds_events%ROWTYPE;
    l_event_reason_comment_rec   lds_comments%ROWTYPE;
    l_target_lot_varchar_id      VARCHAR2 (200);
    l_target_system_code         VARCHAR2 (200);
  BEGIN
    SELECT lotid,system_code
      INTO l_target_lot_varchar_id,l_target_system_code
      FROM lds_lots
     WHERE id = p_target_lot_id;


    FOR event IN list_of_events (p_source_lot_id, p_target_lot_id)
    LOOP
      l_has_events:=TRUE; 
      l_temp_event := NULL;
      l_temp_event := duplicate_event_row (event);

      l_temp_event.parent_evt_id := event.id;
      l_temp_event.lot_id := p_target_lot_id;
      l_temp_event.origin_evt_id := COALESCE (event.origin_evt_id, event.id);
      -- l_temp_event.copy_reason := event.dependant_event_type;

      l_temp_event.target_area :=
        COALESCE (ldsi_cspec.get_effective_event_area (p_channel_type    => event.channel_type,
                                                       p_lotid           => l_target_lot_varchar_id,
                                                       p_source_system   => l_target_system_code,
                                                       p_area            => event.target_area),
                  event.target_area);

      INSERT INTO lds_events VALUES l_temp_event
        RETURNING id INTO l_temp_event.id;

      l_event_reason_comment_rec := copy_comment (event.channel_type, l_temp_event.id, event.id);

      INSERT INTO lds_comments
           VALUES l_event_reason_comment_rec;

      -- COPY DOCUMENTS
      copy_documents (p_source_event => event.id, p_target_event => l_temp_event.id);
    END LOOP;

    IF l_has_events THEN    COMMIT; END IF;

  EXCEPTION
    WHEN OTHERS
    THEN
      ROLLBACK;
      RAISE;
  END copy_events;


FUNCTION duplicate_event_row (source_event IN lds_events%ROWTYPE)
    RETURN lds_events%ROWTYPE
  IS
    l_temp_event   lds_events%ROWTYPE;
  BEGIN
    l_temp_event := source_event;
    l_temp_event.id := NULL;
    l_temp_event.created_by := NULL;
    l_temp_event.created_date := NULL;
    l_temp_event.modified_by := NULL;
    l_temp_event.modified_date := NULL;
    l_temp_event.copy_ny := 'Y';
    RETURN l_temp_event;
  END duplicate_event_row;

编辑一:打开的光标毕竟解决了问题。 查询说明计划:

Plan
SELECT STATEMENT  ALL_ROWSCost: 1,084  Bytes: 167  Cardinality: 1                       
    11 SORT ORDER BY  Cost: 1,084  Bytes: 167  Cardinality: 1                   
        10 FILTER               
            7 NESTED LOOPS ANTI  Cost: 1,083  Bytes: 167  Cardinality: 1            
                4 HASH JOIN  Cost: 1,080  Bytes: 160  Cardinality: 1        
                    2 TABLE ACCESS BY INDEX ROWID TABLE LDS_OWNER.LDS_EVENTS Cost: 2  Bytes: 96  Cardinality: 1     
                        1 INDEX RANGE SCAN INDEX LDS_OWNER.EVT_LOT_STATE_ESCALATED_I Cost: 1  Cardinality: 1  
                    3 TABLE ACCESS FULL TABLE LCC_OWNER.LCC_CIF_EVENT_CHANGES Cost: 1,077  Bytes: 2,880  Cardinality: 45    
                6 TABLE ACCESS BY INDEX ROWID TABLE LDS_OWNER.LDS_EVENTS Cost: 3  Bytes: 7  Cardinality: 1          
                    5 INDEX RANGE SCAN INDEX LDS_OWNER.EVT_LOT_FK_I Cost: 1  Cardinality: 3     
            9 TABLE ACCESS BY INDEX ROWID TABLE LDS_OWNER.LDS_EVENTS Cost: 3  Bytes: 7  Cardinality: 1              
                8 INDEX RANGE SCAN INDEX LDS_OWNER.EVT_LOT_FK_I Cost: 1  Cardinality: 3         

编辑两个用批量收集更改光标,性能更好。

【问题讨论】:

    标签: oracle plsql oracle11g


    【解决方案1】:

    我无法添加 cmets,所以我必须在这里回答 - 抱歉。

    尝试对代码中的每个操作执行类似的操作

    declare
    
      start_time        timestamp;
      end_time         timestamp;
      l_duration number(10,3); 
      begin
        start_time := systimestamp;
        do something..
        end_time := systimestamp;
    
        l_lock_duration := ROUND(EXTRACT( SECOND FROM end_time - start_time ) +
                           EXTRACT( MINUTE FROM end_time - start_time ) * 60 +
                           EXTRACT( HOUR   FROM end_time - start_time ) * 60 * 60,
                           3);
      end;
    

    也许这个长响应只是为了打开光标。第一步,您必须检查每个操作的持续时间。

    【讨论】:

    • 你说的很对,85.868。一定是你提到的光标打开。
    • SQL 查询看起来并不复杂。能否附上查询的解释计划?
    • 接缝光标毕竟不是问题。仍然需要大量时间。
    猜你喜欢
    • 2021-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-27
    相关资源
    最近更新 更多