Oracle查询执行计划

Oracle查询执行计划,oracle,indexing,sql-execution-plan,Oracle,Indexing,Sql Execution Plan,我对Oracle查询的执行计划有点困惑。这在IBM AIX 6.1平台上的Oracle Enterprise Edition 11.2.0.1.0中。我有一个表TEST1(100万行)和另一个表TEST2(50000行)。两个表都有相同的列。有一个视图创建为这两个表的并集。我正在对此视图启动一个查询,WHERE子句中有一个索引列。我能发现的是,没有使用索引,导致了完整的表扫描。稍微修改一下查询,它就开始使用索引。我想知道这个特殊的改变是如何导致计划改变的 请在下面找到完整的DDL+DML。我举了

我对Oracle查询的执行计划有点困惑。这在IBM AIX 6.1平台上的Oracle Enterprise Edition 11.2.0.1.0中。我有一个表TEST1(100万行)和另一个表TEST2(50000行)。两个表都有相同的列。有一个视图创建为这两个表的并集。我正在对此视图启动一个查询,WHERE子句中有一个索引列。我能发现的是,没有使用索引,导致了完整的表扫描。稍微修改一下查询,它就开始使用索引。我想知道这个特殊的改变是如何导致计划改变的

请在下面找到完整的DDL+DML。我举了一个简单的例子。实际的模式和需求要复杂一些。事实上,所讨论的查询是由OCI代码生成器动态构造和执行的。我在这里的目的不是要找到替代方案,而是要真正理解计划更改背后的逻辑推理(在这两者之间,我是一名应用程序程序员,而不是数据库管理员)。非常感谢你的帮助

DROP TABLE TEST1 CASCADE CONSTRAINTS ;  
DROP TABLE TEST2 CASCADE CONSTRAINTS ;  

CREATE TABLE TEST1  
(  
    ID      NUMBER(20)     NOT NULL,  
    NAME    VARCHAR2(40),  
    DAY     NUMBER(20)  
)  
PARTITION BY RANGE (DAY)  
(  
    PARTITION P001 VALUES LESS THAN (2),  
    PARTITION P002 VALUES LESS THAN (3),  
    PARTITION P003 VALUES LESS THAN (4),  
    PARTITION P004 VALUES LESS THAN (5),  
    PARTITION P005 VALUES LESS THAN (6),  
    PARTITION P006 VALUES LESS THAN (7),  
    PARTITION P007 VALUES LESS THAN (8),  
    PARTITION P008 VALUES LESS THAN (9),  
    PARTITION P009 VALUES LESS THAN (10),  
    PARTITION P010 VALUES LESS THAN (11),  
    PARTITION P011 VALUES LESS THAN (12),  
    PARTITION P012 VALUES LESS THAN (13),  
    PARTITION P013 VALUES LESS THAN (14),  
    PARTITION P014 VALUES LESS THAN (15),  
    PARTITION P015 VALUES LESS THAN (16),  
    PARTITION P016 VALUES LESS THAN (17),  
    PARTITION P017 VALUES LESS THAN (18),  
    PARTITION P018 VALUES LESS THAN (19),  
    PARTITION P019 VALUES LESS THAN (20),  
    PARTITION P020 VALUES LESS THAN (21),  
    PARTITION P021 VALUES LESS THAN (22),  
    PARTITION P022 VALUES LESS THAN (23),  
    PARTITION P023 VALUES LESS THAN (24),  
    PARTITION P024 VALUES LESS THAN (25),  
    PARTITION P025 VALUES LESS THAN (26),  
    PARTITION P026 VALUES LESS THAN (27),  
    PARTITION P027 VALUES LESS THAN (28),  
    PARTITION P028 VALUES LESS THAN (29),  
    PARTITION P029 VALUES LESS THAN (30),  
    PARTITION P030 VALUES LESS THAN (31)  
) ;  

CREATE INDEX IX_ID on TEST1 (ID) INITRANS 4 STORAGE(FREELISTS 16) LOCAL  
(  
    PARTITION P001,  
    PARTITION P002,  
    PARTITION P003,  
    PARTITION P004,  
    PARTITION P005,  
    PARTITION P006,  
    PARTITION P007,  
    PARTITION P008,  
    PARTITION P009,  
    PARTITION P010,  
    PARTITION P011,  
    PARTITION P012,  
    PARTITION P013,  
    PARTITION P014,  
    PARTITION P015,  
    PARTITION P016,  
    PARTITION P017,  
    PARTITION P018,  
    PARTITION P019,  
    PARTITION P020,  
    PARTITION P021,  
    PARTITION P022,  
    PARTITION P023,  
    PARTITION P024,  
    PARTITION P025,  
    PARTITION P026,  
    PARTITION P027,  
    PARTITION P028,  
    PARTITION P029,  
    PARTITION P030  
) ;  

CREATE TABLE TEST2  
(  
    ID      NUMBER(20)      PRIMARY KEY   NOT NULL,  
    NAME    VARCHAR2(40),  
    DAY     NUMBER(20)  
) ;  

CREATE OR REPLACE VIEW TEST_V AS  
SELECT  
    ID, NAME, DAY  
FROM  
    TEST1  
UNION  
SELECT  
    ID, NAME, DAY  
FROM  
    TEST2 ;  

begin  
    for count in 1..1000000  
    loop  
        insert into test1 values(count, 'John', mod(count, 30) + 1) ;  
    end loop ;  
end ;  
/  

begin  
    for count in 1000000..1050000  
    loop  
        insert into test2 values(count, 'Mary', mod(count, 30) + 1) ;  
    end loop ;  
end ;  
/  

commit ;  

set lines 300 ;  
set pages 1000 ;  

-- Actual query  
explain plan for  
    SELECT Key FROM  
    (  
        WITH recs AS  
        (  
            SELECT * FROM TEST_V WHERE ID = 70000  
        )  
        (  
            SELECT 1 AS Key FROM recs WHERE NAME = 'John'  
        )  
        UNION  
        (  
            SELECT 2 AS Key FROM recs WHERE NAME = 'Mary'  
        )  
    ) ;  

select * from table(dbms_xplan.display()) ;  

PLAN_TABLE_OUTPUT  
------------------------------------------------------------------------------------------------------------------------------------------  
| Id  | Operation                   | Name                         | Rows  | Bytes  | TempSpc | Cost (%CPU)  |    Time  | Pstart | Pstop |  
------------------------------------------------------------------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT            |                              | 1611K | 4721K  |         |   13559 (1)  | 00:02:43 |        |       |  
|   1 |  VIEW                       |                              | 1611K | 4721K  |         |   13559 (1)  | 00:02:43 |        |       |  
|   2 |   TEMP TABLE TRANSFORMATION |                              |       |        |         |              |          |        |       |  
|   3 |    LOAD AS SELECT           | SYS_TEMP_0FD9D6610_34D3B6C   |       |        |         |              |          |        |       |  
|*  4 |     VIEW                    | TEST_V                       | 805K  | 36M    |         |   10403 (1)  | 00:02:05 |        |       |  
|   5 |      SORT UNIQUE            |                              | 805K  | 36M    |   46M   |   10403 (8)  | 00:02:05 |        |       |  
|   6 |       UNION-ALL             |                              |       |        |         |              |          |        |       |  
|   7 |        PARTITION RANGE ALL  |                              | 752K  | 34M    |         |   721 (1)    | 00:00:09 |    1   |   30  |  
|   8 |     TABLE ACCESS FULL       | TEST1                        | 752K  | 34M    |         |   721 (1)    | 00:00:09 |    1   |   30  |  
|   9 |        TABLE ACCESS FULL    | TEST2                        | 53262 | 2496K  |         |   68 (0)     | 00:00:01 |        |       |  
|  10 |    SORT UNIQUE              |                              | 1611K | 33M    |   43M   |   13559 (51) | 00:02:43 |        |       |  
|  11 |     UNION-ALL               |                              |       |        |         |              |          |        |       |  
|* 12 |      VIEW                   |                              | 805K  | 16M    |         |   1429 (1)   | 00:00:18 |        |       |  
|  13 |       TABLE ACCESS FULL     | SYS_TEMP_0FD9D6610_34D3B6C   | 805K  | 36M    |         |   1429 (1)   | 00:00:18 |        |       |  
|* 14 |      VIEW                   |                              | 805K  | 16M    |         |   1429 (1)   | 00:00:18 |        |       |  
|  15 |       TABLE ACCESS FULL     | SYS_TEMP_0FD9D6610_34D3B6C   | 805K  | 36M    |         |   1429 (1)   | 00:00:18 |        |       |  
------------------------------------------------------------------------------------------------------------------------------------------  

Predicate Information (identified by operation id):  
---------------------------------------------------  
   4 - filter("ID"=70000)  
  12 - filter("NAME"='John')  
  14 - filter("NAME"='Mary')  


-- Modified query (only change is absence of outermost SELECT)  
explain plan for  
    WITH recs AS  
    (  
        SELECT * FROM TEST_V WHERE ID = 70000  
    )  
    (  
        SELECT 1 AS Key FROM recs WHERE NAME = 'John'  
    )  
    UNION  
    (  
        SELECT 2 AS Key FROM recs WHERE NAME = 'Mary'  
    ) ;  

select * from table(dbms_xplan.display()) ;  

PLAN_TABLE_OUTPUT  
-----------------------------------------------------------------------------------------------------------------------------------------  
| Id  | Operation                                | Name                       | Rows  | Bytes | Cost (%CPU) | Time     | Pstart | Pstop |  
-----------------------------------------------------------------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT                         |                            |   4   |  88   |    6 (67)   | 00:00:01 |        |       |  
|   1 |  TEMP TABLE TRANSFORMATION               |                            |       |       |             |          |        |       |  
|   2 |   LOAD AS SELECT                         | SYS_TEMP_0FD9D6611_34D3B6C |       |       |             |          |        |       |  
|   3 |    VIEW                                  | TEST_V                     |   2   |  96   |    4 (50)   | 00:00:01 |        |       |  
|   4 |     SORT UNIQUE                          |                            |   2   |  96   |    4 (75)   | 00:00:01 |        |       |  
|   5 |      UNION-ALL                           |                            |       |       |             |          |        |       |  
|   6 |       PARTITION RANGE ALL                |                            |   1   |  48   |    1 (0)    | 00:00:01 |    1   |   30  |  
|   7 |        TABLE ACCESS BY LOCAL INDEX ROWID | TEST1                      |   1   |  48   |    1 (0)    | 00:00:01 |    1   |   30  |  
|*  8 |     INDEX RANGE SCAN                     | IX_ID                      |   1   |       |    1 (0)    | 00:00:01 |    1   |   30  |  
|   9 |       TABLE ACCESS BY INDEX ROWID        | TEST2                      |   1   |  48   |    1 (0)    | 00:00:01 |        |       |  
|* 10 |        INDEX UNIQUE SCAN                 | SYS_C001242692             |   1   |       |    1 (0)    | 00:00:01 |        |       |  
|  11 |   SORT UNIQUE                            |                            |   4   |  88   |    6 (67)   | 00:00:01 |        |       |  
|  12 |    UNION-ALL                             |                            |       |       |             |          |        |       |  
|* 13 |     VIEW                                 |                            |   2   |  44   |    2 (0)    | 00:00:01 |        |       |  
|  14 |      TABLE ACCESS FULL                   | SYS_TEMP_0FD9D6611_34D3B6C |   2   |  96   |    2 (0)    | 00:00:01 |        |       |  
|* 15 |     VIEW                                 |                            |   2   |  44   |    2 (0)    | 00:00:01 |        |       |  
|  16 |      TABLE ACCESS FULL                   | SYS_TEMP_0FD9D6611_34D3B6C |   2   |  96   |    2 (0)    | 00:00:01 |        |       |  
-----------------------------------------------------------------------------------------------------------------------------------------  

Predicate Information (identified by operation id):  
---------------------------------------------------  
   8 - access("ID"=70000)  
  10 - access("ID"=70000)  
  13 - filter("NAME"='John')  
  15 - filter("NAME"='Mary')  

quit ;  
谢谢和问候,

Reji

我无法在11.2.0.3中重现这一点,我认为对于这种行为没有一个合乎逻辑的解释,除了:您遇到了一个bug,这显然在11.2.0.3中得到了解决

在我看来,有一件事立即引起了我的注意,那就是缺少对象统计信息,而且如果您的输出是完整的,那么OPTIMIZER_DYNAMIC_SAMPLING设置为0。您可以尝试使用OPTIMIZER_DYNAMIC_SAMPLING=2进行复制。在这种情况下,如果缺少对象统计信息,则动态采样器将起作用。顺便说一句:不要使用此功能而不是正确的优化器统计信息。有关动态采样的详细信息

在您的问题和脚本/测试用例中,您尝试使用append和nologging。这仅适用于批量插入,不适用于具有值的行插入。每次插入都会发生这样的情况:向上推高高水位线,并在空闲块中转储一个完整的数据块,在您的情况下,该块只有一行。。。。幸运的是,数据库忽略了这个指令


在向表激发SQL之前,请确保为其提供优化器统计信息。这肯定会对您的案例有所帮助。

我在上重现了这个问题:您是否给出了解释计划的所有输出?谢谢Florin。我第一次看到这个网站(SQLFIDLE)。如果我知道的话,我可能会在那里创建样本。在发布之前,格式化计划花了将近半个小时:(图形计划看起来也非常漂亮和有用。谢谢ik_zelf。我给出的计划已经完成。此外,计划下方的“注释”表示动态采样(2级)已使用。我也将在11.2.0.3.0上进行一次尝试。关于/*+append*/hint和nologging,感谢您纠正我的错误。我在我的框中尝试了查询和数据的各种组合。我只是想避免在这些实验中创建日志。快速谷歌搜索建议了此提示,我没有费心验证,因为它只是一个spike代码。