Oracle表连接的优化案例(十七)

驱动表的限制条件有索引

/*
 结论: Nested Loops Join连接优化,驱动表的限制条件有索引!
*/

--环境构造
--研究Nested Loops Join访问次数前准备工作
DROP TABLE t1 CASCADE CONSTRAINTS PURGE; 
DROP TABLE t2 CASCADE CONSTRAINTS PURGE; 
CREATE TABLE t1 (
     id NUMBER NOT NULL,
     n NUMBER,
     contents VARCHAR2(4000)
   )
   ; 
CREATE TABLE t2 (
     id NUMBER NOT NULL,
     t1_id NUMBER NOT NULL,
     n NUMBER,
     contents VARCHAR2(4000)
   )
   ; 
execute dbms_random.seed(0); 
INSERT INTO t1
     SELECT  rownum,  rownum, dbms_random.string('a', 50)
       FROM dual
     CONNECT BY level <= 100
      ORDER BY dbms_random.random; 
INSERT INTO t2 SELECT rownum, rownum, rownum, dbms_random.string('b', 50) FROM dual CONNECT BY level <= 100000
    ORDER BY dbms_random.random; 
COMMIT; 
select count(*) from t1;
select count(*) from t2;


--Nested Loops Join两表无索引试验
set linesize 1000
set autotrace off
alter session set statistics_level=all ;
SELECT /*+ leading(t1) use_nl(t2) */ *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n = 19;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
-------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |      1 |00:00:00.01 |    1014 |
|   1 |  NESTED LOOPS      |      |      1 |      1 |      1 |00:00:00.01 |    1014 |
|*  2 |   TABLE ACCESS FULL| T1   |      1 |      1 |      1 |00:00:00.01 |       8 |
|*  3 |   TABLE ACCESS FULL| T2   |      1 |      1 |      1 |00:00:00.01 |    1006 |
-------------------------------------------------------------------------------------
   2 - filter("T1"."N"=19)
   3 - filter("T1"."ID"="T2"."T1_ID")

----两表无索引场合如果不用HINT,一般走Hash Join
alter session set statistics_level=all ;
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n = 19;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
----------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |      1 |00:00:00.06 |    1013 |       |       |          |
|*  1 |  HASH JOIN         |      |      1 |      1 |      1 |00:00:00.06 |    1013 |   742K|   742K|  376K (0)|
|*  2 |   TABLE ACCESS FULL| T1   |      1 |      1 |      1 |00:00:00.01 |       7 |       |       |          |
|   3 |   TABLE ACCESS FULL| T2   |      1 |    100K|    100K|00:00:00.02 |    1006 |       |       |          |
----------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("T1"."ID"="T2"."T1_ID")
   2 - filter("T1"."N"=19)



---对t1表的限制条件建索引
CREATE INDEX t1_n ON t1 (n);
---有了限制条件的索引,Nested Loops Join性能略有提升
set linesize 1000
alter session set statistics_level=all ;
SELECT /*+ leading(t1) use_nl(t2) */ *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n = 19;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

--------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |      |      1 |        |      1 |00:00:00.06 |    1009 |   1007 |
|   1 |  NESTED LOOPS                |      |      1 |      1 |      1 |00:00:00.06 |    1009 |   1007 |
|   2 |   TABLE ACCESS BY INDEX ROWID| T1   |      1 |      1 |      1 |00:00:00.01 |       3 |      6 |
|*  3 |    INDEX RANGE SCAN          | T1_N |      1 |      1 |      1 |00:00:00.01 |       2 |      1 |
|*  4 |   TABLE ACCESS FULL          | T2   |      1 |      1 |      1 |00:00:00.05 |    1006 |   1001 |
--------------------------------------------------------------------------------------------------------
   3 - access("T1"."N"=19)
   4 - filter("T1"."ID"="T2"."T1_ID")


---不过发现,增加了索引后Oracle不用HINT,还是走HASH连接。
alter session set statistics_level=all ;
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n = 19;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
--------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |      |      1 |        |      1 |00:00:00.05 |    1008 |       |       |          |
|*  1 |  HASH JOIN                   |      |      1 |      1 |      1 |00:00:00.05 |    1008 |   742K|   742K|  350K (0)|
|   2 |   TABLE ACCESS BY INDEX ROWID| T1   |      1 |      1 |      1 |00:00:00.01 |       2 |       |       |          |
|*  3 |    INDEX RANGE SCAN          | T1_N |      1 |      1 |      1 |00:00:00.01 |       1 |       |       |          |
|   4 |   TABLE ACCESS FULL          | T2   |      1 |  89127 |    100K|00:00:00.02 |    1006 |       |       |          |
--------------------------------------------------------------------------------------------------------------------------
   1 - access("T1"."ID"="T2"."T1_ID")
   3 - access("T1"."N"=19)

/*
原因在于,这个T1表总记录也不过100条,所以用索引效果并没有很明显,如果这个T1表记录有几十万上百万条,那检索一条记录出来
,用索引效果就非常明显了!
*/

 被驱动表限制条件有索引  

/*
 结论: 给Nested Loops Join连接优化,被驱动表的连接条件有索引!
*/

--环境构造
--研究Nested Loops Join访问次数前准备工作
DROP TABLE t1 CASCADE CONSTRAINTS PURGE; 
DROP TABLE t2 CASCADE CONSTRAINTS PURGE; 
CREATE TABLE t1 (
     id NUMBER NOT NULL,
     n NUMBER,
     contents VARCHAR2(4000)
   )
   ; 
CREATE TABLE t2 (
     id NUMBER NOT NULL,
     t1_id NUMBER NOT NULL,
     n NUMBER,
     contents VARCHAR2(4000)
   )
   ; 
execute dbms_random.seed(0); 
INSERT INTO t1
     SELECT  rownum,  rownum, dbms_random.string('a', 50)
       FROM dual
     CONNECT BY level <= 100
      ORDER BY dbms_random.random; 
INSERT INTO t2 SELECT rownum, rownum, rownum, dbms_random.string('b', 50) FROM dual CONNECT BY level <= 100000
    ORDER BY dbms_random.random; 
COMMIT; 
select count(*) from t1;
select count(*) from t2;

--(对驱动表t1表的限制条件建索引),如下
CREATE INDEX t1_n ON t1 (n);

--(对被驱动表t2表的连接条件建索引),如下:
CREATE INDEX t2_t1_id ON t2(t1_id);

----这下表连接性能有了大幅度提升
alter session set statistics_level=all ;
SELECT /*+ leading(t1) use_nl(t2) */ *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n = 19;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

----------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads|
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |          |      1 |        |      1 |00:00:00.01 |       7 |    4 |
|   1 |  NESTED LOOPS                 |          |      1 |        |      1 |00:00:00.01 |       7 |    4 |
|   2 |   NESTED LOOPS                |          |      1 |      1 |      1 |00:00:00.01 |       6 |    4 |
|   3 |    TABLE ACCESS BY INDEX ROWID| T1       |      1 |      1 |      1 |00:00:00.01 |       3 |    0 |
|*  4 |     INDEX RANGE SCAN          | T1_N     |      1 |      1 |      1 |00:00:00.01 |       2 |    0 |
|*  5 |    INDEX RANGE SCAN           | T2_T1_ID |      1 |      1 |      1 |00:00:00.01 |       3 |    4 |
|   6 |   TABLE ACCESS BY INDEX ROWID | T2       |      1 |      1 |      1 |00:00:00.01 |       1 |    0 |
-----------------------------------------------------------------------------------------------------------
   4 - access("T1"."N"=19)
   5 - access("T1"."ID"="T2"."T1_ID")
--性能有了大幅度提升,BUFFERS居然只有7


---增加了索引后Oracle不用HINT,终于自己去选择Nested Loops Join
alter session set statistics_level=all ;
SELECT *
FROM t1, t2
WHERE t1.id = t2.t1_id
AND t1.n = 19;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
----------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |          |      1 |        |      1 |00:00:00.01 |       7 |
|   1 |  NESTED LOOPS                 |          |      1 |        |      1 |00:00:00.01 |       7 |
|   2 |   NESTED LOOPS                |          |      1 |      1 |      1 |00:00:00.01 |       6 |
|   3 |    TABLE ACCESS BY INDEX ROWID| T1       |      1 |      1 |      1 |00:00:00.01 |       3 |
|*  4 |     INDEX RANGE SCAN          | T1_N     |      1 |      1 |      1 |00:00:00.01 |       2 |
|*  5 |    INDEX RANGE SCAN           | T2_T1_ID |      1 |      1 |      1 |00:00:00.01 |       3 |
|   6 |   TABLE ACCESS BY INDEX ROWID | T2       |      1 |      1 |      1 |00:00:00.01 |       1 |
----------------------------------------------------------------------------------------------------
   4 - access("T1"."N"=19)
   5 - access("T1"."ID"="T2"."T1_ID")

  

猜你喜欢

转载自www.cnblogs.com/sunliyuan/p/12448171.html