PL / SQL - 检查过程参数会减慢其执行速度

时间:2016-10-12 14:00:13

标签: sql oracle plsql

我执行以下程序:

DECLARE

 PROCEDURE my_proc(arg1    IN NUMBER,
                   arg2    IN NUMBER)
 IS
      ltimestamp_start       timestamp;
      ltimestamp_stop        timestamp;
      linterval_diff         interval day to second;
 BEGIN    
    ltimestamp_start := systimestamp;

    UPDATE transfers t1
    SET t1.trn_valid = 'Y'
    WHERE EXISTS( 
        SELECT 1 
        FROM transfers t2
        JOIN tasks u1 ON trn_tsk_id = u1.tsk_id
        WHERE t1.trn_id = t2.trn_id
            AND t2.trn_pom_id = arg1
            AND u1.tsk_type <> 'TT'
            AND (
                (arg2 IS NULL AND t2.trn_ord IN ('W', 'K') AND t2.trn_type <> 'P' AND t2.trn_mng IN ('0', '1')) OR
                (arg2 IS NOT NULL AND t2.trn_ord IN ('W', 'K') AND t2.trn_type <> 'P' AND arg2 = t2.trn_id)
            )
    );

    ltimestamp_stop := systimestamp;
    linterval_diff := ltimestamp_stop - ltimestamp_start;
    DBMS_OUTPUT.PUT_LINE(EXTRACT(SECOND FROM linterval_diff));
 END;

BEGIN
  my_proc(200, 300);
END;

平均而言,它需要0,085939。

但是,如果我发表评论:

--(arg2 IS NULL AND t2.trn_ord IN ('W', 'K') AND t2.trn_type <> 'P' AND t2.trn_mng IN ('0', '1')) OR

执行只需要0,000275s。

在这种情况下,arg2等于300,但检查条件&#34; arg2 IS NULL&#34;大大减慢了程序。

为什么我会得到如此奇怪的结果?

1 个答案:

答案 0 :(得分:2)

当您注释掉(arg2 IS NULL...时,您只留下t2.trn_id = arg2的强制条件,为Oracle的优化工具提供了非常明确的访问路径(假设t2.trn_idt2.trn_pom_id)。

Oracle的优化器有很多技巧可以将OR个查询转换为多个部分,每个部分都以不同的方式访问数据并且运行良好。在这种情况下,甲骨文的伎俩可能会失败。

您可以尝试通过拆分它的逻辑来帮助CBO。我相信您的查询等同于以下内容,Oracle的CBO可能会有更好的时间:

UPDATE transfers t1
SET t1.trn_valid = 'Y'
WHERE EXISTS( 
    SELECT 1 
    FROM transfers t2
    JOIN tasks u1 ON trn_tsk_id = u1.tsk_id
    WHERE t1.trn_id = t2.trn_id
        AND t2.trn_pom_id = arg1
        AND u1.tsk_type <> 'TT'
        AND t2.trn_ord IN ('W', 'K')
        AND t2.trn_type <> 'P'
        AND t2.trn_mng IN ('0', '1')
        AND arg2 IS NULL
    UNION ALL
    SELECT 1 
    FROM transfers t2
    JOIN tasks u1 ON trn_tsk_id = u1.tsk_id
    WHERE t1.trn_id = t2.trn_id
        AND t2.trn_pom_id = arg1
        AND u1.tsk_type <> 'TT'
        AND t2.trn_ord IN ('W', 'K')
        AND t2.trn_type <> 'P'
        AND arg2 = t2.trn_id
        AND arg2 IS NOT NULL
);