暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

SQL优化 - 表连接的 索引覆盖优化方式

SQL优化 - 表连接的 索引覆盖优化方式

表连接的索引覆盖考虑:

1 驱动表和被驱动表的索引需要覆盖到where条件涉及的列,和连接条件的列,还有select查询的列
2 当驱动表和被驱动表的where条件(除了连接列)选择性好,返回的结果集少的时候,where条件的列考虑放到索引列的前边:连接的列放到索引列的后边
3 当被驱动表的where条件选择性不好的时候,但是驱动表只有少量的结果集的时候,执行计划可能考虑NL,连接列考虑放到索引列的前边:where列考虑放到索引列的后边
4 如果被驱动表除了连接列之外,没有其它条件,HASH连接的方式只能是全表扫描,NL连接才考虑使用连接列上的索引
5 查询列可以考虑放在索引的最后
6 如果是NL的连接,如果被驱动表连接列选择性很好,也可以考虑使用连接列的单列索引
7 如果是HASH的连接,通常被驱动表的连接列放到组合索引where列的后面; 
8 如果不是高并发执行的业务SQL,都不用考虑建索引,维护索引也是需要成本的。

需要优化的SQL类似如下

with aa as (
select t.* from XXXX_NN.XXXXXX_XXXXXXXt2 t  
where t.yyyy_id in ( select xxx_id from XXXX_NN.XXXXXX_XXXXXt1 n where n.flags = 11 and n.ver_flags =2)   
     and t.ver_flags = 2 
     and t.flags in (0, 10) 
     and t.xxxxbbs is not null
) select t.*,rowid  from XXXX_NN.XXXXXX_XXXXXXXt2 t 
where xxx_id in(select xxx_id from aa)
;
Plan hash value: 3977745688
------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name             | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |
------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                  |       |       |       |  1682K(100)|          |       |       |
|*  1 |  HASH JOIN RIGHT SEMI |                  |  3630K|   495M|    39M|  1682K  (1)| 05:36:35 |       |       |
|   2 |   VIEW                | VW_NSO_1         |  1667K|    20M|       |   645K  (2)| 02:09:08 |       |       |
|*  3 |    HASH JOIN          |                  |  1667K|    79M|  7752K|   645K  (2)| 02:09:08 |       |       |
|   4 |     PARTITION LIST ALL|                  |   293K|  4304K|       |   130K  (1)| 00:26:04 |     1 |   116 |
|*  5 |      TABLE ACCESS FULL| XXXXXX_XXXXXt1   |   293K|  4304K|       |   130K  (1)| 00:26:04 |     1 |   116 |
|   6 |     PARTITION LIST ALL|                  |    19M|   664M|       |   470K  (2)| 01:34:07 |     1 |   116 |
|*  7 |      TABLE ACCESS FULL| XXXXXX_XXXXXXXt2 |    19M|   664M|       |   470K  (2)| 01:34:07 |     1 |   116 |
|   8 |   PARTITION LIST ALL  |                  |    84M|    10G|       |   470K  (2)| 01:34:02 |     1 |   116 |
|   9 |    TABLE ACCESS FULL  | XXXXXX_XXXXXXXt2 |    84M|    10G|       |   470K  (2)| 01:34:02 |     1 |   116 |
------------------------------------------------------------------------------------------------------------------
1 - access("xxx_id"="xxx_id")
3 - access("T"."yyyy_id"="xxx_id")
5 - filter(("N"."FLAGS"=11 AND "N"."VER_FLAGS"=2))
7 - filter(("T"."VER_FLAGS"=2 AND INTERNAL_FUNCTION("T"."FLAGS") AND "T"."xxxxbbs" IS NOT NULL))

-- SQL执行的等待事件:
EVENT                                       TOTAL WAIT CLASS
---------------------------------------- -------- ---------------
db file scattered read                        434 User_IO
read by other session                         257 User_IO
CPU                                           122 CPU
db file parallel read                          42 User_IO
latch: cache buffers lru chain                 27 Other
gc cr multi block request                      19 Cluster
db file sequential read                        14 User_IO
gc current block 2-way                          3 Cluster
gc current grant busy                           2 Cluster
gc buffer busy acquire                          2 Cluster
latch: object queue header operation            2 Other
gc cr disk read                                 1 Cluster
gc cr block busy                                1 Cluster
gc cr grant 2-way                               1 Cluster


SQL执行统计信息,逻辑读看着不多才350万,但是物理读超乎想像,已经不够显示了
      CPU(MS)  ELA(MS)     DISK       GET     ROWS      ROWS APPLI(MS) CONCUR(MS) CLUSTER(MS) USER_IO(MS)    PLSQL     JAVA
EXEC PRE EXEC PRE EXEC PRE EXEC  PRE EXEC PRE EXEC PRE FETCH  PER EXEC   PER EXEC    PER EXEC    PER EXEC PER EXEC PER EXEC SQL_PROFILE
---- -------- -------- -------- --------- -------- --------- --------- ---------- ----------- ----------- -------- -------- ---------------
1      87,163  928,482 ######## 3,516,627        0         0         0         12      30,378     735,061        0        0

           PLAN  CHI USER     CPU(MS)  ELA(MS)     DISK        GET     ROWS      ROWS APPLI(MS) CONCUR(MS) CLUSTER(MS) USER_IO(MS) FIRST_LOAD_TIME
EXEC HASH VALUE  NUM NAME    PRE EXEC PRE EXEC PRE EXEC   PRE EXEC PRE EXEC PRE FETCH  PER EXEC   PER EXEC    PER EXEC    PER EXEC LAST_LOAD_TIME
---- ---------- ---- ------- -------- -------- -------- ---------- -------- --------- --------- ---------- ----------- ----------- ----------------------
1    3977745688    0 XXXX_NN  87,163  928,482 ########  3,516,627        0         0         0         12      30,378     735,061 10-28/16:4.10-28/16:4

优化方案:使用索引覆盖

create index XXXX_NN.IND_NET_LFUSE_VER521 on XXXX_NN.XXXXXX_XXXXXt1(ver_flags,flags,xxx_id) parallel 16 online;
alter index XXXX_NN.IND_NET_LFUSE_VER521  parallel 1;
drop index XXXX_NN.IND_NET_LFUSE_VER52;


create index XXXX_NN.IND_LS_METROLOGY_SITE on XXXX_NN.XXXXXX_XXXXXXXt2(ver_flags,flags,xxxxbbs,yyyy_id,xxx_id) parallel 16 online;
alter index XXXX_NN.IND_LS_METROLOGY_SITE  parallel 1;
drop index XXXX_NN.IND_LS_METROLOGY_SITEID;


-- 使用HINT 优化之后:
-- set autot traceonly实际执行 查看统计信息
with aa as (
 select t.* from XXXX_NN.XXXXXX_XXXXXXXt2 t  
 where t.yyyy_id in ( select xxx_id from XXXX_NN.XXXXXX_XXXXXt1 n where n.flags = 11 and n.ver_flags =2)   
      and t.ver_flags = 2 
      and t.flags in (0, 10) 
      and t.xxxxbbs is not null
 ) select /*+index(t PK2_XXXXXX_XXXXXXXt2)*/t.*,rowid  from XXXX_NN.XXXXXX_XXXXXXXt2 t 
 where xxx_id in(select xxx_id from aa);

no rows selected
Elapsed: 00:01:33.04


实际执行
Plan hash value: 3739262284
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name                  | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time   | Pstart| Pstop | A-Rows |   A-Time   | Buffers | Reads  |  OMem   |  1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                       |      1 |        |       |       |  8277K(100)|          |       |       |      0 |00:01:32.97 |     129K|    129K|         |       |          |
|   1 |  NESTED LOOPS                       |                       |      1 |        |       |       |            |          |       |       |      0 |00:01:32.97 |     129K|    129K|         |       |          |
|   2 |   NESTED LOOPS                      |                       |      1 |   3544K|   479M|       |  8277K  (1)| 27:35:36 |       |       |      0 |00:01:32.97 |     129K|    129K|         |       |          |
|   3 |    VIEW                             | VW_NSO_1              |      1 |   1613K|    20M|       |   196K  (1)| 00:39:23 |       |       |      0 |00:01:32.97 |     129K|    129K|         |       |          |
|   4 |     HASH UNIQUE                     |                       |      1 |   1613K|    76M|       |            |          |       |       |      0 |00:01:32.97 |     129K|    129K|   823K  |  823K |          |
|*  5 |      HASH JOIN                      |                       |      1 |   1613K|    76M|  7432K|   196K  (1)| 00:39:23 |       |       |      0 |00:01:32.97 |     129K|    129K|    23M  | 3383K |   37M (0)|
|*  6 |       INDEX RANGE SCAN              | IND_NET_LFUSE_VER521  |      1 |    281K|  4126K|       |  1116   (1)| 00:00:14 |       |       |    772K|00:00:02.25 |    3174 |   3171 |         |       |          |
|   7 |       INLIST ITERATOR               |                       |      1 |        |       |       |            |          |       |       |     17M|00:01:20.70 |     126K|    126K|         |       |          |
|*  8 |        INDEX RANGE SCAN             | IND_LS_METROLOGY_SITE |      2 |     20M|   672M|       |   150K  (1)| 00:30:05 |       |       |     17M|00:01:16.51 |     126K|    126K|         |       |          |
|*  9 |    INDEX RANGE SCAN                 | PK2_XXXXXX_XXXXXXXt2  |      0 |      2 |       |       |     3   (0)| 00:00:01 |       |       |      0 |00:00:00.01 |       0 |      0 |         |       |          |
|  10 |   TABLE ACCESS BY GLOBAL INDEX ROWID| XXXXXX_XXXXXXXt2      |      0 |      2 |   258 |       |     5   (0)| 00:00:01 | ROWID | ROWID |      0 |00:00:00.01 |       0 |      0 |         |       |          |
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   5 - access("T"."yyyy_id"="xxx_id")
   6 - access("N"."VER_FLAGS"=2 AND "N"."FLAGS"=11)
   8 - access("T"."VER_FLAGS"=2 AND (("T"."FLAGS"=0 OR "T"."FLAGS"=10)))
       filter("T"."xxxxbbs" IS NOT NULL)
   9 - access("xxx_id"="xxx_id")

-- 执行计划中 索引 IND_LS_METROLOGY_SITE 的访问使用了"INLIST ITERATOR"的方式, starts为2 索引访问了2次,是因为 条件 flags in (0, 10)  所以定位不同叶子块访问了2次

2 两个很大基数的分区表关联,实际关联返回行数却很少(上面SQL执行的时候已经没有返回),CBO却没办法确切的评估返回行数:
3 优化之前的执行计划评估返回167万,实际返回2行,优化之后的执行计划评估返回161万行,实际返回0行

4 如果两个1亿数据量的表做关联,1个表全是奇数,1个表全是偶数,实际返回行数确实为0,只能实际的关联匹配之后才知道实际返回行数

验证测试索引覆盖:

连接查询使用索引覆盖测试

-- 构造数据
create table t1 as select * from dba_objects;
create table t2 as select * from dba_objects;
create index IDX_T11 on t1(NAMESPACE,data_object_id,object_id);
create index idx_t22 on t2(status,object_id);
-- SQL
select t1.object_id from t1 where t1.NAMESPACE in(4,5) and 
data_object_id in(select object_id from t2 where STATUS='11')
;
------------------------------------------------------------------------------
| Id  | Operation          | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |         |  6036 |   123K|    81   (2)| 00:00:01 |
|*  1 |  HASH JOIN SEMI    |         |  6036 |   123K|    81   (2)| 00:00:01 |
|   2 |   INLIST ITERATOR  |         |       |       |            |          |
|*  3 |    INDEX RANGE SCAN| IDX_T11 |  6036 | 78468 |    22   (0)| 00:00:01 |
|*  4 |   INDEX RANGE SCAN | IDX_T22 | 22099 |   172K|    58   (0)| 00:00:01 |
------------------------------------------------------------------------------



-- 构造随机数据
drop table t1 purge;
drop table t2 purge;
create table t1 as select * from dba_objects;
create table t2 as select * from dba_objects;

update t1 set object_id=ceil(dbms_random.value(1,100000)),DATA_OBJECT_ID=ceil(dbms_random.value(1,100000));
update t2 set object_id=ceil(dbms_random.value(1,100000)),DATA_OBJECT_ID=ceil(dbms_random.value(1,100000));
update t1 set SUBOBJECT_NAME=to_char(ceil(dbms_random.value(1,60000))) where SUBOBJECT_NAME is null and rownum<=80000;
update t1 set STATUS=to_char(ceil(mod(OBJECT_ID,dbms_random.value(1,14))));
update t2 set STATUS=to_char(ceil(mod(OBJECT_ID,dbms_random.value(1,14))));
update t1 set NAMESPACE=to_char(ceil(mod(OBJECT_ID,dbms_random.value(1,14))));
update t2 set NAMESPACE=to_char(ceil(mod(OBJECT_ID,dbms_random.value(1,14))));

update t2 set STATUS='11' where status<>'11' and rownum<=20000;
update t2 set NAMESPACE=4 where NAMESPACE<>4 and rownum<=60000;

update t1 set NAMESPACE=2 where NAMESPACE<>2 and rownum<=50000;
update t1 set STATUS='10' where STATUS not in ('0','10') and rownum<=60000;


select object_id,DATA_OBJECT_ID,count(1) from t1 group by object_id,DATA_OBJECT_ID having count(1)>1;
select object_id,DATA_OBJECT_ID,count(1) from t2 group by object_id,DATA_OBJECT_ID having count(1)>1;

select NAMESPACE,count(1) from t2 group by NAMESPACE order by 2;
select STATUS,count(1)    from t2 group by STATUS order by 2;

select NAMESPACE,count(1) from t1 group by NAMESPACE;
select STATUS,count(1)    from t1 group by STATUS order by 2;


-- 构建索引
-- 唯一索引
create unique index pk_t1 on t1(object_id,DATA_OBJECT_ID);
create unique index pk_t2 on t2(object_id,DATA_OBJECT_ID);
-- 使用索引覆盖: t2
create index ix_t2_SNO on t2(STATUS,NAMESPACE,object_id); 
create index ix_t2_OSN on t2(object_id,STATUS,NAMESPACE); 
-- 使用索引覆盖: t1
create index ix_t1_NSSDO on t1(NAMESPACE,STATUS,SUBOBJECT_NAME,DATA_OBJECT_ID,object_id);
create index ix_t1_DNSSO on t1(DATA_OBJECT_ID,NAMESPACE,STATUS,SUBOBJECT_NAME,object_id);
create index ix_t1_NDO   on t1(NAMESPACE,DATA_OBJECT_ID,OBJECT_ID);


测试1: 类似于生产上的SQL

with /*test1*/aa as (
 select t.object_id from t1 t  
 where t.DATA_OBJECT_ID in (select object_id from t2 n where n.STATUS = '11' and n.NAMESPACE =5)
 and t.NAMESPACE = 2   and t.STATUS in ('0','10')     and t.SUBOBJECT_NAME is not null
) select w.*,rowid  from t1 w 
where object_id in(select object_id from aa);

-- autot执行计划-实际执行并没有产生这个执行计划
---------------------------------------------------------------------------------------
| Id  | Operation               | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |             |   870 |   112K|   543   (1)| 00:00:01 |
|*  1 |  HASH JOIN RIGHT SEMI   |             |   870 |   112K|   543   (1)| 00:00:01 |
|   2 |   VIEW                  | VW_NSO_1    |   572 |  7436 |   116   (1)| 00:00:01 |
|*  3 |    HASH JOIN            |             |   572 | 18876 |   116   (1)| 00:00:01 |
|*  4 |     INDEX RANGE SCAN    | IX_T2_SNO   |   503 |  5533 |     3   (0)| 00:00:01 |
|*  5 |     INDEX FAST FULL SCAN| IX_T1_DNSSO | 39891 |   857K|   113   (1)| 00:00:01 |
|   6 |   TABLE ACCESS FULL     | T1          | 91338 |    10M|   427   (1)| 00:00:01 |
---------------------------------------------------------------------------------------

-- 实际执行计划1: 第一次执行 with内部NL 外部HASH
SQL_ID  6btba7a5ahzyk, child number 0
------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation            | Name        | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |             |      1 |        |       |   543 (100)|          |     59 |00:00:00.05 |    1600 |   1583 |       |       |          |
|*  1 |  HASH JOIN RIGHT SEMI|             |      1 |    870 |   112K|   543   (1)| 00:00:01 |     59 |00:00:00.05 |    1600 |   1583 |  2168K|  2168K| 1469K (0)|
|   2 |   VIEW               | VW_NSO_1    |      1 |    572 |  7436 |   116   (1)| 00:00:01 |     29 |00:00:00.01 |      58 |     49 |       |       |          |
|   3 |    NESTED LOOPS      |             |      1 |    572 | 18876 |   116   (1)| 00:00:01 |     29 |00:00:00.01 |      58 |     49 |       |       |          |
|*  4 |     INDEX RANGE SCAN | IX_T2_SNO   |      1 |    503 |  5533 |     3   (0)| 00:00:01 |     54 |00:00:00.01 |       2 |      2 |       |       |          |
|*  5 |     INDEX RANGE SCAN | IX_T1_DNSSO |     54 |      1 |    22 |   113   (1)| 00:00:01 |     29 |00:00:00.01 |      56 |     47 |       |       |          |
|   6 |   TABLE ACCESS FULL  | T1          |      1 |  91338 |    10M|   427   (1)| 00:00:01 |  91338 |00:00:00.02 |    1542 |   1534 |       |       |          |
------------------------------------------------------------------------------------------------------------------------------------------------------------------
   1 - access("OBJECT_ID"="OBJECT_ID")
   4 - access("N"."STATUS"='11' AND "N"."NAMESPACE"=5)
   5 - access("T"."DATA_OBJECT_ID"="OBJECT_ID" AND "T"."NAMESPACE"=2)
       filter(("T"."SUBOBJECT_NAME" IS NOT NULL AND INTERNAL_FUNCTION("T"."STATUS")))

-- 实际执行计划2: 第二次执行 with内部NL 外部使用NL
SQL_ID  6btba7a5ahzyk, child number 1
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name        | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |      1 |        |       |    61 (100)|          |     59 |00:00:00.01 |     155 |       |       |          |
|   1 |  NESTED LOOPS                |             |      1 |     59 |  7847 |    61   (2)| 00:00:01 |     59 |00:00:00.01 |     155 |       |       |          |
|   2 |   NESTED LOOPS               |             |      1 |     59 |  7847 |    61   (2)| 00:00:01 |     59 |00:00:00.01 |      96 |       |       |          |
|   3 |    VIEW                      | VW_NSO_1    |      1 |      1 |    13 |    57   (0)| 00:00:01 |     29 |00:00:00.01 |      58 |       |       |          |
|   4 |     HASH UNIQUE              |             |      1 |      1 |    33 |            |          |     29 |00:00:00.01 |      58 |  2170K|  2170K| 2555K (0)|
|   5 |      NESTED LOOPS            |             |      1 |      1 |    33 |    57   (0)| 00:00:01 |     29 |00:00:00.01 |      58 |       |       |          |
|*  6 |       INDEX RANGE SCAN       | IX_T2_SNO   |      1 |     54 |   594 |     3   (0)| 00:00:01 |     54 |00:00:00.01 |       2 |       |       |          |
|*  7 |       INDEX RANGE SCAN       | IX_T1_DNSSO |     54 |      1 |    22 |     1   (0)| 00:00:01 |     29 |00:00:00.01 |      56 |       |       |          |
|*  8 |    INDEX RANGE SCAN          | PK_T1       |     29 |      2 |       |     1   (0)| 00:00:01 |     59 |00:00:00.01 |      38 |       |       |          |
|   9 |   TABLE ACCESS BY INDEX ROWID| T1          |     59 |     59 |  7080 |     3   (0)| 00:00:01 |     59 |00:00:00.01 |      59 |       |       |          |
----------------------------------------------------------------------------------------------------------------------------------------------------------------
   6 - access("N"."STATUS"='11' AND "N"."NAMESPACE"=5)
   7 - access("T"."DATA_OBJECT_ID"="OBJECT_ID" AND "T"."NAMESPACE"=2)
       filter(("T"."SUBOBJECT_NAME" IS NOT NULL AND INTERNAL_FUNCTION("T"."STATUS")))
   8 - access("OBJECT_ID"="OBJECT_ID")

测试2: 在外部HINT使用主键索引

with /*test2*/aa as (
 select t.object_id from t1 t  
 where t.DATA_OBJECT_ID in (select object_id from t2 n where n.STATUS = '11' and n.NAMESPACE =5)
 and t.NAMESPACE = 2   and t.STATUS in ('0','10')     and t.SUBOBJECT_NAME is not null
) select /*+index(w PK_T1)*/w.*,rowid  from t1 w 
where object_id in(select object_id from aa);

-- 执行计划:  执行执行是测试1中的第2种执行计划
SQL_ID  a1gzm69hdn5rr, child number 0
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name        | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |      1 |        |       |  1833 (100)|          |     59 |00:00:00.01 |     155 |    136 |       |       |          |
|   1 |  NESTED LOOPS                |             |      1 |    870 |   112K|  1833   (1)| 00:00:01 |     59 |00:00:00.01 |     155 |    136 |       |       |          |
|   2 |   NESTED LOOPS               |             |      1 |   1144 |   112K|  1833   (1)| 00:00:01 |     59 |00:00:00.01 |      96 |     78 |       |       |          |
|   3 |    VIEW                      | VW_NSO_1    |      1 |    572 |  7436 |   116   (1)| 00:00:01 |     29 |00:00:00.01 |      58 |     49 |       |       |          |
|   4 |     HASH UNIQUE              |             |      1 |    572 | 18876 |            |          |     29 |00:00:00.01 |      58 |     49 |  2170K|  2170K| 1374K (0)|
|   5 |      NESTED LOOPS            |             |      1 |    572 | 18876 |   116   (1)| 00:00:01 |     29 |00:00:00.01 |      58 |     49 |       |       |          |
|*  6 |       INDEX RANGE SCAN       | IX_T2_SNO   |      1 |    503 |  5533 |     3   (0)| 00:00:01 |     54 |00:00:00.01 |       2 |      2 |       |       |          |
|*  7 |       INDEX RANGE SCAN       | IX_T1_DNSSO |     54 |      1 |    22 |   113   (1)| 00:00:01 |     29 |00:00:00.01 |      56 |     47 |       |       |          |
|*  8 |    INDEX RANGE SCAN          | PK_T1       |     29 |      2 |       |     1   (0)| 00:00:01 |     59 |00:00:00.01 |      38 |     29 |       |       |          |
|   9 |   TABLE ACCESS BY INDEX ROWID| T1          |     59 |      2 |   240 |     3   (0)| 00:00:01 |     59 |00:00:00.01 |      59 |     58 |       |       |          |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   6 - access("N"."STATUS"='11' AND "N"."NAMESPACE"=5)
   7 - access("T"."DATA_OBJECT_ID"="OBJECT_ID" AND "T"."NAMESPACE"=2)
       filter(("T"."SUBOBJECT_NAME" IS NOT NULL AND INTERNAL_FUNCTION("T"."STATUS")))
   8 - access("OBJECT_ID"="OBJECT_ID")

测试3: 在外部HINT使用主键索引 指定hash连接

with /*test3*/aa as (
 select t.object_id from t1 t  
 where t.DATA_OBJECT_ID in (select object_id from t2 n where n.STATUS = '11' and n.NAMESPACE =5)
 and t.NAMESPACE = 2   and t.STATUS in ('0','10')     and t.SUBOBJECT_NAME is not null
) select /*+index(w PK_T1) use_hash(w) */w.*,rowid  from t1 w 
where object_id in(select object_id from aa);
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name        | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |             |      1 |        |       | 91663 (100)|          |     59 |00:00:00.40 |   91949 |   1700 |       |       |          |
|*  1 |  HASH JOIN RIGHT SEMI                |             |      1 |    870 |   112K| 91663   (1)| 00:00:04 |     59 |00:00:00.40 |   91949 |   1700 |  2168K|  2168K| 1483K (0)|
|   2 |   VIEW                               | VW_NSO_1    |      1 |    572 |  7436 |   116   (1)| 00:00:01 |     29 |00:00:00.03 |     416 |      0 |       |       |          |
|*  3 |    HASH JOIN                         |             |      1 |    572 | 18876 |   116   (1)| 00:00:01 |     29 |00:00:00.03 |     416 |      0 |  2293K|  2293K| 1591K (0)|
|*  4 |     INDEX RANGE SCAN                 | IX_T2_SNO   |      1 |    503 |  5533 |     3   (0)| 00:00:01 |     54 |00:00:00.01 |       2 |      0 |       |       |          |
|*  5 |     INDEX FAST FULL SCAN             | IX_T1_DNSSO |      1 |  39891 |   857K|   113   (1)| 00:00:01 |  60774 |00:00:00.01 |     414 |      0 |       |       |          |
|   6 |   TABLE ACCESS BY INDEX ROWID BATCHED| T1          |      1 |  91338 |    10M| 91547   (1)| 00:00:04 |  91338 |00:00:00.34 |   91533 |   1700 |       |       |          |
|   7 |    INDEX FULL SCAN                   | PK_T1       |      1 |  91338 |       |   254   (1)| 00:00:01 |  91338 |00:00:00.02 |     257 |    210 |       |       |          |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   1 - access("OBJECT_ID"="OBJECT_ID")
   3 - access("T"."DATA_OBJECT_ID"="OBJECT_ID")
   4 - access("N"."STATUS"='11' AND "N"."NAMESPACE"=5)
   5 - filter(("T"."SUBOBJECT_NAME" IS NOT NULL AND "T"."NAMESPACE"=2 AND INTERNAL_FUNCTION("T"."STATUS")))
由于外部t1表除了object_id并没有其它条件,如果使用HASH,将对t1进行查询全表的结果集,再做hash半连接
又指定的索引的HINT,所有全部扫描索引之后又回表,逻辑读高达9万,比全表扫描的成本1542高59倍

测试4:在with内部使用hash

with /*test4*/aa as (
 select /*+use_hash(t)*/t.object_id from t1 t  
 where t.DATA_OBJECT_ID in (select object_id from t2 n where n.STATUS = '11' and n.NAMESPACE =5)
 and t.NAMESPACE = 2   and t.STATUS in ('0','10')     and t.SUBOBJECT_NAME is not null
) select w.*,rowid  from t1 w 
where object_id in(select object_id from aa);

-- autot 执行计划-- 
---------------------------------------------------------------------------------------
| Id  | Operation               | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |             |   870 |   112K|   543   (1)| 00:00:01 |
|*  1 |  HASH JOIN RIGHT SEMI   |             |   870 |   112K|   543   (1)| 00:00:01 |
|   2 |   VIEW                  | VW_NSO_1    |   572 |  7436 |   116   (1)| 00:00:01 |
|*  3 |    HASH JOIN            |             |   572 | 18876 |   116   (1)| 00:00:01 |
|*  4 |     INDEX RANGE SCAN    | IX_T2_SNO   |   503 |  5533 |     3   (0)| 00:00:01 |
|*  5 |     INDEX FAST FULL SCAN| IX_T1_DNSSO | 39891 |   857K|   113   (1)| 00:00:01 |
|   6 |   TABLE ACCESS FULL     | T1          | 91338 |    10M|   427   (1)| 00:00:01 |
---------------------------------------------------------------------------------------
   1 - access("OBJECT_ID"="OBJECT_ID")
   3 - access("T"."DATA_OBJECT_ID"="OBJECT_ID")
   4 - access("N"."STATUS"='11' AND "N"."NAMESPACE"=5)
   5 - filter("T"."SUBOBJECT_NAME" IS NOT NULL AND "T"."NAMESPACE"=2 AND
              ("T"."STATUS"='0' OR "T"."STATUS"='10'))

实际执行计划1:
SQL_ID  dzs43s0uy04da, child number 0
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation               | Name        | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |             |      1 |        |       |   543 (100)|          |     59 |00:00:00.08 |    1958 |   1944 |       |       |          |
|*  1 |  HASH JOIN RIGHT SEMI   |             |      1 |    870 |   112K|   543   (1)| 00:00:01 |     59 |00:00:00.08 |    1958 |   1944 |  2168K|  2168K| 1441K (0)|
|   2 |   VIEW                  | VW_NSO_1    |      1 |    572 |  7436 |   116   (1)| 00:00:01 |     29 |00:00:00.03 |     416 |    410 |       |       |          |
|*  3 |    HASH JOIN            |             |      1 |    572 | 18876 |   116   (1)| 00:00:01 |     29 |00:00:00.03 |     416 |    410 |  2293K|  2293K| 1539K (0)|
|*  4 |     INDEX RANGE SCAN    | IX_T2_SNO   |      1 |    503 |  5533 |     3   (0)| 00:00:01 |     54 |00:00:00.01 |       2 |      2 |       |       |          |
|*  5 |     INDEX FAST FULL SCAN| IX_T1_DNSSO |      1 |  39891 |   857K|   113   (1)| 00:00:01 |  60774 |00:00:00.01 |     414 |    408 |       |       |          |
|   6 |   TABLE ACCESS FULL     | T1          |      1 |  91338 |    10M|   427   (1)| 00:00:01 |  91338 |00:00:00.02 |    1542 |   1534 |       |       |          |
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
   1 - access("OBJECT_ID"="OBJECT_ID")
   3 - access("T"."DATA_OBJECT_ID"="OBJECT_ID")
   4 - access("N"."STATUS"='11' AND "N"."NAMESPACE"=5)
   5 - filter(("T"."SUBOBJECT_NAME" IS NOT NULL AND "T"."NAMESPACE"=2 AND INTERNAL_FUNCTION("T"."STATUS")))

实际执行计划2: with 内部使用hash,外部使用索引
SQL_ID  dzs43s0uy04da, child number 1
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name        | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |      1 |        |       |   204 (100)|          |     59 |00:00:00.04 |     513 |       |       |          |
|   1 |  NESTED LOOPS                |             |      1 |     59 |  7847 |   204   (1)| 00:00:01 |     59 |00:00:00.04 |     513 |       |       |          |
|   2 |   NESTED LOOPS               |             |      1 |     59 |  7847 |   204   (1)| 00:00:01 |     59 |00:00:00.04 |     454 |       |       |          |
|   3 |    VIEW                      | VW_NSO_1    |      1 |     29 |   377 |   116   (1)| 00:00:01 |     29 |00:00:00.03 |     416 |       |       |          |
|   4 |     HASH UNIQUE              |             |      1 |     29 |   957 |            |          |     29 |00:00:00.03 |     416 |  2170K|  2170K| 2538K (0)|
|*  5 |      HASH JOIN               |             |      1 |     29 |   957 |   116   (1)| 00:00:01 |     29 |00:00:00.03 |     416 |  2293K|  2293K| 1574K (0)|
|*  6 |       INDEX RANGE SCAN       | IX_T2_SNO   |      1 |     54 |   594 |     3   (0)| 00:00:01 |     54 |00:00:00.01 |       2 |       |       |          |
|*  7 |       INDEX FAST FULL SCAN   | IX_T1_DNSSO |      1 |  39891 |   857K|   113   (1)| 00:00:01 |  60774 |00:00:00.02 |     414 |       |       |          |
|*  8 |    INDEX RANGE SCAN          | PK_T1       |     29 |      2 |       |     1   (0)| 00:00:01 |     59 |00:00:00.01 |      38 |       |       |          |
|   9 |   TABLE ACCESS BY INDEX ROWID| T1          |     59 |      2 |   240 |     3   (0)| 00:00:01 |     59 |00:00:00.01 |      59 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
   5 - access("T"."DATA_OBJECT_ID"="OBJECT_ID")
   6 - access("N"."STATUS"='11' AND "N"."NAMESPACE"=5)
   7 - filter(("T"."SUBOBJECT_NAME" IS NOT NULL AND "T"."NAMESPACE"=2 AND INTERNAL_FUNCTION("T"."STATUS")))
   8 - access("OBJECT_ID"="OBJECT_ID")
内部hash的实际逻辑读416,比之前NL的连接方式的逻辑读58高7倍

测试5: 在外部HINT使用主键索引 在with内部使用hash

-- 5.1 不指定使用的索引覆盖
with /*test5.1*/aa as (
 select /*+use_hash(t)*/t.object_id from t1 t  
 where t.DATA_OBJECT_ID in (select object_id from t2 n where n.STATUS = '11' and n.NAMESPACE =5)
 and t.NAMESPACE = 2   and t.STATUS in ('0','10')     and t.SUBOBJECT_NAME is not null
) select /*+index(w PK_T1)*/w.*,rowid  from t1 w 
where object_id in(select object_id from aa);
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name        | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |      1 |        |       |  1833 (100)|          |     59 |00:00:00.12 |     513 |    536 |       |       |          |
|   1 |  NESTED LOOPS                |             |      1 |    870 |   112K|  1833   (1)| 00:00:01 |     59 |00:00:00.12 |     513 |    536 |       |       |          |
|   2 |   NESTED LOOPS               |             |      1 |   1144 |   112K|  1833   (1)| 00:00:01 |     59 |00:00:00.08 |     454 |    461 |       |       |          |
|   3 |    VIEW                      | VW_NSO_1    |      1 |    572 |  7436 |   116   (1)| 00:00:01 |     29 |00:00:00.05 |     416 |    410 |       |       |          |
|   4 |     HASH UNIQUE              |             |      1 |    572 | 18876 |            |          |     29 |00:00:00.05 |     416 |    410 |  2170K|  2170K| 1335K (0)|
|*  5 |      HASH JOIN               |             |      1 |    572 | 18876 |   116   (1)| 00:00:01 |     29 |00:00:00.05 |     416 |    410 |  2293K|  2293K| 1590K (0)|
|*  6 |       INDEX RANGE SCAN       | IX_T2_SNO   |      1 |    503 |  5533 |     3   (0)| 00:00:01 |     54 |00:00:00.01 |       2 |      2 |       |       |          |
|*  7 |       INDEX FAST FULL SCAN   | IX_T1_DNSSO |      1 |  39891 |   857K|   113   (1)| 00:00:01 |  60774 |00:00:00.02 |     414 |    408 |       |       |          |
|*  8 |    INDEX RANGE SCAN          | PK_T1       |     29 |      2 |       |     1   (0)| 00:00:01 |     59 |00:00:00.03 |      38 |     51 |       |       |          |
|   9 |   TABLE ACCESS BY INDEX ROWID| T1          |     59 |      2 |   240 |     3   (0)| 00:00:01 |     59 |00:00:00.04 |      59 |     75 |       |       |          |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   5 - access("T"."DATA_OBJECT_ID"="OBJECT_ID")
   6 - access("N"."STATUS"='11' AND "N"."NAMESPACE"=5)
   7 - filter(("T"."SUBOBJECT_NAME" IS NOT NULL AND "T"."NAMESPACE"=2 AND INTERNAL_FUNCTION("T"."STATUS")))
   8 - access("OBJECT_ID"="OBJECT_ID")
和上面测试4的第2个实际执行计划一致

-- 5.2 指定不使用5.1使用的覆盖索引
with /*test5.2*/aa as (
 select /*+use_hash(t) no_index(t IX_T1_DNSSO) no_index(@SEL$2 n IX_T2_SNO)*/t.object_id from t1 t  
 where t.DATA_OBJECT_ID in (select object_id from t2 n where n.STATUS = '11' and n.NAMESPACE =5)
 and t.NAMESPACE = 2   and t.STATUS in ('0','10')     and t.SUBOBJECT_NAME is not null
) select /*+index(w PK_T1)*/w.*,rowid  from t1 w 
where object_id in(select object_id from aa);
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name        | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |      1 |        |       |  1906 (100)|          |     59 |00:00:00.06 |     789 |    672 |       |       |          |
|   1 |  NESTED LOOPS                |             |      1 |    870 |   112K|  1906   (1)| 00:00:01 |     59 |00:00:00.06 |     789 |    672 |       |       |          |
|   2 |   NESTED LOOPS               |             |      1 |   1144 |   112K|  1906   (1)| 00:00:01 |     59 |00:00:00.06 |     730 |    672 |       |       |          |
|   3 |    VIEW                      | VW_NSO_1    |      1 |    572 |  7436 |   188   (1)| 00:00:01 |     29 |00:00:00.06 |     692 |    672 |       |       |          |
|   4 |     HASH UNIQUE              |             |      1 |    572 | 18876 |            |          |     29 |00:00:00.06 |     692 |    672 |  2170K|  2170K| 1377K (0)|
|*  5 |      HASH JOIN               |             |      1 |    572 | 18876 |   188   (1)| 00:00:01 |     29 |00:00:00.06 |     692 |    672 |  2293K|  2293K| 1576K (0)|
|*  6 |       INDEX FAST FULL SCAN   | IX_T2_OSN   |      1 |    503 |  5533 |    75   (0)| 00:00:01 |     54 |00:00:00.02 |     278 |    272 |       |       |          |
|*  7 |       INDEX FAST FULL SCAN   | IX_T1_NSSDO |      1 |  39891 |   857K|   113   (1)| 00:00:01 |  60774 |00:00:00.02 |     414 |    400 |       |       |          |
|*  8 |    INDEX RANGE SCAN          | PK_T1       |     29 |      2 |       |     1   (0)| 00:00:01 |     59 |00:00:00.01 |      38 |      0 |       |       |          |
|   9 |   TABLE ACCESS BY INDEX ROWID| T1          |     59 |      2 |   240 |     3   (0)| 00:00:01 |     59 |00:00:00.01 |      59 |      0 |       |       |          |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   5 - access("T"."DATA_OBJECT_ID"="OBJECT_ID")
   6 - filter(("N"."NAMESPACE"=5 AND "N"."STATUS"='11'))
   7 - filter(("T"."SUBOBJECT_NAME" IS NOT NULL AND "T"."NAMESPACE"=2 AND INTERNAL_FUNCTION("T"."STATUS")))
   8 - access("OBJECT_ID"="OBJECT_ID")
1 虽然同样是使用索引覆盖,但是索引的使用访问方式,实际消耗的逻辑读却不一样
2 对t2表的索引使用方式从范围扫描,变成了索引快速全扫,从直接定位访问变成了filter的执行计划
3 with内部的t1表索引有一个和t2表关联的列,DATA_OBJECT_ID,一个查询返回的列obect_id,还有3个where条件中的列,一共有5个列,都是使用快速全扫过滤的方式

测试6: 在外部HINT使用主键索引 在with内部使用hash 在外部使用HASH

with /*test6*/aa as (
 select /*+use_hash(t)*/t.object_id from t1 t  
 where t.DATA_OBJECT_ID in (select object_id from t2 n where n.STATUS = '11' and n.NAMESPACE =5)
 and t.NAMESPACE = 2   and t.STATUS in ('0','10')     and t.SUBOBJECT_NAME is not null
) select /*+index(w PK_T1) use_hash(w)*/w.*,rowid  from t1 w 
where object_id in(select object_id from aa);
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name        | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |             |      1 |        |       | 91663 (100)|          |     59 |00:00:00.40 |   91949 |   1700 |       |       |          |
|*  1 |  HASH JOIN RIGHT SEMI                |             |      1 |    870 |   112K| 91663   (1)| 00:00:04 |     59 |00:00:00.40 |   91949 |   1700 |  2168K|  2168K| 1483K (0)|
|   2 |   VIEW                               | VW_NSO_1    |      1 |    572 |  7436 |   116   (1)| 00:00:01 |     29 |00:00:00.03 |     416 |      0 |       |       |          |
|*  3 |    HASH JOIN                         |             |      1 |    572 | 18876 |   116   (1)| 00:00:01 |     29 |00:00:00.03 |     416 |      0 |  2293K|  2293K| 1591K (0)|
|*  4 |     INDEX RANGE SCAN                 | IX_T2_SNO   |      1 |    503 |  5533 |     3   (0)| 00:00:01 |     54 |00:00:00.01 |       2 |      0 |       |       |          |
|*  5 |     INDEX FAST FULL SCAN             | IX_T1_DNSSO |      1 |  39891 |   857K|   113   (1)| 00:00:01 |  60774 |00:00:00.01 |     414 |      0 |       |       |          |
|   6 |   TABLE ACCESS BY INDEX ROWID BATCHED| T1          |      1 |  91338 |    10M| 91547   (1)| 00:00:04 |  91338 |00:00:00.34 |   91533 |   1700 |       |       |          |
|   7 |    INDEX FULL SCAN                   | PK_T1       |      1 |  91338 |       |   254   (1)| 00:00:01 |  91338 |00:00:00.02 |     257 |    210 |       |       |          |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   1 - access("OBJECT_ID"="OBJECT_ID")
   3 - access("T"."DATA_OBJECT_ID"="OBJECT_ID")
   4 - access("N"."STATUS"='11' AND "N"."NAMESPACE"=5)
   5 - filter(("T"."SUBOBJECT_NAME" IS NOT NULL AND "T"."NAMESPACE"=2 AND INTERNAL_FUNCTION("T"."STATUS")))
和之前测试3,对外部表hash的逻辑读一致,逻辑读高得无法想像

测试7: 在with内部使用hash 但是被驱动表变成子查询中的表

-- 7.1 把namespace条件改成=14 返回结果较少
with /*test7.1*/aa as (
 select t.object_id from t1 t  
 where t.DATA_OBJECT_ID in (select object_id from t2 n where n.STATUS = '11' and n.NAMESPACE =5)
 and t.NAMESPACE = 14   and t.STATUS in ('0','10')     and t.SUBOBJECT_NAME is not null
) select w.*,rowid  from t1 w 
where object_id in(select object_id from aa);

-- 执行计划
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name        | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |      1 |        |       |   183 (100)|          |      0 |00:00:00.01 |       5 |       |       |          |
|   1 |  NESTED LOOPS                |             |      1 |     90 | 11970 |   183   (1)| 00:00:01 |      0 |00:00:00.01 |       5 |       |       |          |
|   2 |   NESTED LOOPS               |             |      1 |    118 | 11970 |   183   (1)| 00:00:01 |      0 |00:00:00.01 |       5 |       |       |          |
|   3 |    VIEW                      | VW_NSO_1    |      1 |     59 |   767 |     5   (0)| 00:00:01 |      0 |00:00:00.01 |       5 |       |       |          |
|   4 |     HASH UNIQUE              |             |      1 |     59 |  1947 |            |          |      0 |00:00:00.01 |       5 |  1063K|  1063K|          |
|*  5 |      HASH JOIN SEMI          |             |      1 |     59 |  1947 |     5   (0)| 00:00:01 |      0 |00:00:00.01 |       5 |  1753K|  1753K| 1103K (0)|
|*  6 |       INDEX RANGE SCAN       | IX_T1_NSSDO |      1 |     59 |  1298 |     2   (0)| 00:00:01 |      7 |00:00:00.01 |       3 |       |       |          |
|*  7 |       INDEX RANGE SCAN       | IX_T2_SNO   |      1 |    503 |  5533 |     3   (0)| 00:00:01 |     54 |00:00:00.01 |       2 |       |       |          |
|*  8 |    INDEX RANGE SCAN          | PK_T1       |      0 |      2 |       |     1   (0)| 00:00:01 |      0 |00:00:00.01 |       0 |       |       |          |
|   9 |   TABLE ACCESS BY INDEX ROWID| T1          |      0 |      2 |   240 |     3   (0)| 00:00:01 |      0 |00:00:00.01 |       0 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
   5 - access("T"."DATA_OBJECT_ID"="OBJECT_ID")
   6 - access("T"."NAMESPACE"=14)
       filter(("T"."SUBOBJECT_NAME" IS NOT NULL AND INTERNAL_FUNCTION("T"."STATUS")))
   7 - access("N"."STATUS"='11' AND "N"."NAMESPACE"=5)
   8 - access("OBJECT_ID"="OBJECT_ID")
-- 注意1:驱动表变成了首先过滤之后结果集较少的T1,with内部执行的是hash半连接
-- 注意2:驱动表T1的使用的索引已经从之前的 DNSSO 变成了NSSDO  where筛选列在索引前面
-- 注意3:被驱动表T2使用的索引还是where筛选的列在前面的索引,索引中包含了连接查询需要的全部列的信息
-- 注意4:驱动表T1的索引使用方式,如果索引的选择性很好,返回的结果集很少,索引的使用方式就从之前的快速全扫再filter,变成了现在的access再filter


-- 7.2 t2表不使用7.1使用的索引
with /*test7.1*/aa as (
 select /*+ use_hash(@SEL$2 n) no_index(@SEL$2 n IX_T2_SNO)*/t.object_id from t1 t  
 where t.DATA_OBJECT_ID in (select object_id from t2 n where n.STATUS = '11' and n.NAMESPACE =5)
 and t.NAMESPACE = 14   and t.STATUS in ('0','10')     and t.SUBOBJECT_NAME is not null
) select w.*,rowid  from t1 w 
where object_id in(select object_id from aa);

-----------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name        | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |      1 |        |       |   255 (100)|          |      0 |00:00:00.01 |     281 |       |       |          |
|   1 |  NESTED LOOPS                |             |      1 |     90 | 11970 |   255   (1)| 00:00:01 |      0 |00:00:00.01 |     281 |       |       |          |
|   2 |   NESTED LOOPS               |             |      1 |    118 | 11970 |   255   (1)| 00:00:01 |      0 |00:00:00.01 |     281 |       |       |          |
|   3 |    VIEW                      | VW_NSO_1    |      1 |     59 |   767 |    77   (0)| 00:00:01 |      0 |00:00:00.01 |     281 |       |       |          |
|   4 |     HASH UNIQUE              |             |      1 |     59 |  1947 |            |          |      0 |00:00:00.01 |     281 |  1063K|  1063K|          |
|*  5 |      HASH JOIN SEMI          |             |      1 |     59 |  1947 |    77   (0)| 00:00:01 |      0 |00:00:00.01 |     281 |  1753K|  1753K| 1147K (0)|
|*  6 |       INDEX RANGE SCAN       | IX_T1_NSSDO |      1 |     59 |  1298 |     2   (0)| 00:00:01 |      7 |00:00:00.01 |       3 |       |       |          |
|*  7 |       INDEX FAST FULL SCAN   | IX_T2_OSN   |      1 |    503 |  5533 |    75   (0)| 00:00:01 |     54 |00:00:00.01 |     278 |       |       |          |
|*  8 |    INDEX RANGE SCAN          | PK_T1       |      0 |      2 |       |     1   (0)| 00:00:01 |      0 |00:00:00.01 |       0 |       |       |          |
|   9 |   TABLE ACCESS BY INDEX ROWID| T1          |      0 |      2 |   240 |     3   (0)| 00:00:01 |      0 |00:00:00.01 |       0 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
   5 - access("T"."DATA_OBJECT_ID"="OBJECT_ID")
   6 - access("T"."NAMESPACE"=14)
       filter(("T"."SUBOBJECT_NAME" IS NOT NULL AND INTERNAL_FUNCTION("T"."STATUS")))
   7 - filter(("N"."NAMESPACE"=5 AND "N"."STATUS"='11'))
   8 - access("OBJECT_ID"="OBJECT_ID")
-- 注意1:被驱动表t2的覆盖索引的使用方式已经变成了索引快扫再filter的方式,逻辑读为278,比7.1的逻辑读2高136倍
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论