sql - 存储过程 SQL 执行计划

标签 sql oracle sql-execution-plan

我对执行速度非常慢的存储过程感到有些困惑。存储过程基本上包含一个使用传入参数 (in_id) 的查询,并放置在一个游标中,如下所示:

open tmp_cursor for 
select col1, col2, col3
from table1 tab
where ((in_id is null) or (tab.id = in_id));  -- tab.id is the PK

当我使用预定义的值单独获得 SQL 查询的执行计划时,我通过使用索引的查询获得了良好的结果。但是,当我从我的应用程序调用该过程时,我看到没有使用索引并且表进行了完整扫描,从而导致性能下降。
如果我删除 WHERE 子句“(in_id is null)”的第一部分,应用程序的性能又会很快。
为什么在我的应用程序调用期间没有使用索引(传入 in_id)?

最佳答案

in_id is null



我在这里回答了类似的问题 https://stackoverflow.com/a/26633820/3989608

关于 NULL 值和 INDEX 的一些事实:
  • Oracle 中的“正常”B*Tree 中不会输入完全 NULL 键
  • 因此,如果您在 C1 和 C2 上有一个串联索引,那么您可能会在其中找到 NULL 值——因为您可能有一行 C1 为 NULL 但 C2 不是 NULL——该键值将在索引中。

  • 托马斯·凯特 (Thomas Kyte) 的演示的某些部分与此相关:
    ops$tkyte@ORA9IR2> create table t
    2  as
    3  select object_id, owner, object_name
    4    from dba_objects;
    Table created.
    
    ops$tkyte@ORA9IR2> alter table t modify (owner NOT NULL);
    Table altered.
    
    ops$tkyte@ORA9IR2> create index t_idx on t(object_id,owner);
    Index created.
    
    ops$tkyte@ORA9IR2> desc t
    Name                    Null?    Type
    ----------------------- -------- ----------------
    OBJECT_ID                        NUMBER
    OWNER                   NOT NULL VARCHAR2(30)
    OBJECT_NAME                      VARCHAR2(128)
    
    ops$tkyte@ORA9IR2> exec dbms_stats.gather_table_stats(user,'T');
    PL/SQL procedure successfully completed.
    

    好吧,当应用于 OBJECT_ID 时,该索引当然可以用于满足“IS NOT NULL”:
    ops$tkyte@ORA9IR2> set autotrace traceonly explain
    ops$tkyte@ORA9IR2> select * from t where object_id is null;
    
    Execution Plan
    ----------------------------------------------------------
    0      SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=1 Bytes=34)
    1    0   TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=3 Card=1 Bytes=34)
    2    1     INDEX (RANGE SCAN) OF 'T_IDX' (NON-UNIQUE) (Cost=2 Card=1)
    

    事实上——即使表没有任何 NOT NULL 列,或者我们不想/不需要有一个涉及 OWNER 的串联索引——有一种透明的方法可以很容易地找到 NULL OBJECT_ID 值:
    ops$tkyte@ORA9IR2> drop index t_idx;
    Index dropped.
    
    ops$tkyte@ORA9IR2> create index t_idx_new on t(object_id,0);
    Index created.
    
    ops$tkyte@ORA9IR2> set autotrace traceonly explain
    ops$tkyte@ORA9IR2> select * from t where object_id is null;
    
    Execution Plan
    ----------------------------------------------------------
    0      SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=1 Bytes=34)
    1    0   TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=3 Card=1 Bytes=34)
    2    1     INDEX (RANGE SCAN) OF 'T_IDX_NEW' (NON-UNIQUE) (Cost=2 Card=1)
    

    来源:Something about nothing by Thomas Kyte

    关于sql - 存储过程 SQL 执行计划,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29630354/

    相关文章:

    mysql - 表中的自连接和递归选择

    sql - 如何在oracle的emp表中找到前三名最高工资?

    oracle - 构建sql执行计划历史

    Derby 的子查询优化问题

    当索引包含 varchar2 列时 Oracle 不使用索引排序 - NLS_SORT

    sql - 当另一列具有匹配值时,选择一列中具有最大值的行

    mysql - 数据库设计——来自多个来源的独特数据

    php - sql查询速度慢

    php - 如何在 PHP 中获取有关 SQL 警告的更多信息?

    oracle - Oracle 形式的 FRM-40501