[20160125]闭包传递问题.txt

[20160125]闭包传递问题.txt

--所谓闭包传递是指sql语句的谓词条件A=B and B=C 可以推出 A=C. oracle 的 优化器能够利用这个特性优化sql语句。
--但是这些依旧存在一些问题,在电子书<Apress.Expert.Oracle.SQL.Optimization.Deployment.and.Statistics.1430259779.pdf>
--提到一个例子,无法实现闭包传递。自己重复测试看看:


1.环境:
SCOTT@book> @ &r/ver1
PORT_STRING                    VERSION        BANNER
------------------------------ -------------- --------------------------------------------------------------------------------
x86_64/Linux 2.4.xx            11.2.0.4.0     Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

CREATE TABLE t3 AS SELECT ROWNUM c1 FROM DUAL CONNECT BY LEVEL <= 10;
CREATE TABLE t4 AS SELECT MOD (ROWNUM, 10) + 100 c1 FROM DUAL CONNECT BY LEVEL <= 100;
CREATE TABLE t5 AS SELECT MOD (ROWNUM, 10) c1, RPAD ('X', 30) filler FROM DUAL CONNECT BY LEVEL <= 10000;

CREATE INDEX t5_i1 ON t5 (c1);

--分析表。

2.测试1:

SCOTT@book> alter session set statistics_level=all;
Session altered.

SCOTT@book> SELECT COUNT (*) FROM t3, t5 WHERE t3.c1 = t5.c1 AND t3.c1 = 1;
  COUNT(*)
----------
      1000

SCOTT@book> @&r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  dk73qsratggkh, child number 0
-------------------------------------
SELECT COUNT (*) FROM t3, t5 WHERE t3.c1 = t5.c1 AND t3.c1 = 1
Plan hash value: 1275968336
----------------------------------------------------------------------------------------------------------------------------------------------------
| 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 |        |       |     5 (100)|          |      1 |00:00:00.01 |       6 |       |       |          |
|   1 |  SORT AGGREGATE       |       |      1 |      1 |     6 |            |          |      1 |00:00:00.01 |       6 |       |       |          |
|   2 |   MERGE JOIN CARTESIAN|       |      1 |   1000 |  6000 |     5   (0)| 00:00:01 |   1000 |00:00:00.01 |       6 |       |       |          |
|*  3 |    TABLE ACCESS FULL  | T3    |      1 |      1 |     3 |     3   (0)| 00:00:01 |      1 |00:00:00.01 |       2 |       |       |          |
|   4 |    BUFFER SORT        |       |      1 |   1000 |  3000 |     2   (0)| 00:00:01 |   1000 |00:00:00.01 |       4 | 73728 | 73728 |          |
|*  5 |     INDEX RANGE SCAN  | T5_I1 |      1 |   1000 |  3000 |     2   (0)| 00:00:01 |   1000 |00:00:00.01 |       4 |       |       |          |
----------------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1
   3 - SEL$1 / T3@SEL$1
   5 - SEL$1 / T5@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - filter("T3"."C1"=1)
   5 - access("T5"."C1"=1)

--可以发现ID=3,5的access或者filter是C1=1.而且取消了连接条件,变成了CARTESIAN集。

3.测试2:
SCOTT@book> SELECT * FROM t3, t4, t5 WHERE t3.c1 = t4.c1 AND t4.c1 = t5.c1;
no rows selected

SCOTT@book> @&r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  bd3j0xbhyq4yx, child number 0
-------------------------------------
SELECT * FROM t3, t4, t5 WHERE t3.c1 = t4.c1 AND t4.c1 = t5.c1
Plan hash value: 3251999038
-----------------------------------------------------------------------------------------------------------------------------------------------------------
| 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 |        |       |     7 (100)|          |      0 |00:00:00.01 |       4 |       |       |          |
|   1 |  NESTED LOOPS                |       |      1 |      1 |    41 |     7   (0)| 00:00:01 |      0 |00:00:00.01 |       4 |       |       |          |
|   2 |   NESTED LOOPS               |       |      1 |   1000 |    41 |     7   (0)| 00:00:01 |      0 |00:00:00.01 |       4 |       |       |          |
|*  3 |    HASH JOIN                 |       |      1 |      1 |     7 |     6   (0)| 00:00:01 |      0 |00:00:00.01 |       4 |  2440K|  2440K| 1313K (0)|
|   4 |     TABLE ACCESS FULL        | T3    |      1 |     10 |    30 |     3   (0)| 00:00:01 |     10 |00:00:00.01 |       2 |       |       |          |
|   5 |     TABLE ACCESS FULL        | T4    |      1 |    100 |   400 |     3   (0)| 00:00:01 |    100 |00:00:00.01 |       2 |       |       |          |
|*  6 |    INDEX RANGE SCAN          | T5_I1 |      0 |   1000 |       |     1   (0)| 00:00:01 |      0 |00:00:00.01 |       0 |       |       |          |
|   7 |   TABLE ACCESS BY INDEX ROWID| T5    |      0 |      1 |    34 |     1   (0)| 00:00:01 |      0 |00:00:00.01 |       0 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1
   4 - SEL$1 / T3@SEL$1
   5 - SEL$1 / T4@SEL$1
   6 - SEL$1 / T5@SEL$1
   7 - SEL$1 / T5@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("T3"."C1"="T4"."C1")
   6 - access("T4"."C1"="T5"."C1")

--如果执行如下语句是等价的: SELECT * FROM t3, t4, t5 WHERE t3.c1 = t5.c1 AND t4.c1 = t5.c1;

SCOTT@book> SELECT * FROM t3, t4, t5 WHERE t3.c1 = t5.c1 AND t4.c1 = t5.c1;

no rows selected

SCOTT@book> @&r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  g5007pk488f76, child number 0
-------------------------------------
SELECT * FROM t3, t4, t5 WHERE t3.c1 = t5.c1 AND t4.c1 = t5.c1
Plan hash value: 1630033643
-------------------------------------------------------------------------------------------------------------------------------------------------
| 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 |        |       |    24 (100)|          |      0 |00:00:00.01 |      58 |       |       |          |
|*  1 |  HASH JOIN          |      |      1 |      1 |    41 |    24   (0)| 00:00:01 |      0 |00:00:00.01 |      58 |  1021K|  1021K|  159K (0)|
|*  2 |   HASH JOIN         |      |      1 |      1 |    38 |    21   (0)| 00:00:01 |      0 |00:00:00.01 |      58 |  2440K|  2440K| 1230K (0)|
|   3 |    TABLE ACCESS FULL| T4   |      1 |    100 |   400 |     3   (0)| 00:00:01 |    100 |00:00:00.01 |       2 |       |       |          |
|   4 |    TABLE ACCESS FULL| T5   |      1 |  10000 |   332K|    18   (0)| 00:00:01 |  10000 |00:00:00.01 |      56 |       |       |          |
|   5 |   TABLE ACCESS FULL | T3   |      0 |     10 |    30 |     3   (0)| 00:00:01 |      0 |00:00:00.01 |       0 |       |       |          |
-------------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1
   3 - SEL$1 / T4@SEL$1
   4 - SEL$1 / T5@SEL$1
   5 - SEL$1 / T3@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("T3"."C1"="T5"."C1")
   2 - access("T4"."C1"="T5"."C1")

--对比上下执行计划发生了很大变化,连接顺序发生了变化。


4.测试3:
--如果要达到测试1的效果,使用提示:
SELECT /*+ leading(t3 t4 t5)  use_hash(t4) use_nl(t5) */ * FROM t3, t4, t5 WHERE t3.c1 = t5.c1 AND t4.c1 = t5.c1;

SCOTT@book> SELECT /*+ leading(t3 t4 t5)  use_hash(t4) use_nl(t5) */ * FROM t3, t4, t5 WHERE t3.c1 = t5.c1 AND t4.c1 = t5.c1;
no rows selected

Plan hash value: 3284867853
-----------------------------------------------------------------------------------------------------------------------------------------------------------
| 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 |        |       |  1015 (100)|          |      0 |00:00:00.01 |      12 |       |       |          |
|   1 |  NESTED LOOPS                |       |      1 |      1 |    41 |  1015   (0)| 00:00:13 |      0 |00:00:00.01 |      12 |       |       |          |
|   2 |   NESTED LOOPS               |       |      1 |    100K|    41 |  1015   (0)| 00:00:13 |      0 |00:00:00.01 |      12 |       |       |          |
|   3 |    MERGE JOIN CARTESIAN      |       |      1 |   1000 |  7000 |    15   (0)| 00:00:01 |   1000 |00:00:00.01 |       4 |       |       |          |
|   4 |     TABLE ACCESS FULL        | T3    |      1 |     10 |    30 |     3   (0)| 00:00:01 |     10 |00:00:00.01 |       2 |       |       |          |
|   5 |     BUFFER SORT              |       |     10 |    100 |   400 |    12   (0)| 00:00:01 |   1000 |00:00:00.01 |       2 |  4096 |  4096 | 4096  (0)|
|   6 |      TABLE ACCESS FULL       | T4    |      1 |    100 |   400 |     1   (0)| 00:00:01 |    100 |00:00:00.01 |       2 |       |       |          |
|*  7 |    INDEX RANGE SCAN          | T5_I1 |   1000 |    100 |       |     1   (0)| 00:00:01 |      0 |00:00:00.01 |       8 |       |       |          |
|   8 |   TABLE ACCESS BY INDEX ROWID| T5    |      0 |      1 |    34 |     1   (0)| 00:00:01 |      0 |00:00:00.01 |       0 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1
   4 - SEL$1 / T3@SEL$1
   6 - SEL$1 / T4@SEL$1
   7 - SEL$1 / T5@SEL$1
   8 - SEL$1 / T5@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
   7 - access("T4"."C1"="T5"."C1")
       filter("T3"."C1"="T5"."C1")

--实际上并没有实现上面的执行计划,而是产生了CARTESIAN集合。必须要加入t3.c1=t4.c1条件。

SCOTT@book> SELECT /*+ leading(t3 t4 t5)  use_hash(t4) use_nl(t5) */ * FROM t3, t4, t5 WHERE t3.c1 = t5.c1 AND t4.c1 = t5.c1 and t3.c1=t4.c1;
no rows selected

SCOTT@book> @ &r/dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  9nzh9uxm6b11z, child number 0
-------------------------------------
SELECT /*+ leading(t3 t4 t5)  use_hash(t4) use_nl(t5) */ * FROM t3, t4,
t5 WHERE t3.c1 = t5.c1 AND t4.c1 = t5.c1 and t3.c1=t4.c1
Plan hash value: 3251999038
-----------------------------------------------------------------------------------------------------------------------------------------------------------
| 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 |        |       |     7 (100)|          |      0 |00:00:00.01 |       4 |       |       |          |
|   1 |  NESTED LOOPS                |       |      1 |      1 |    41 |     7   (0)| 00:00:01 |      0 |00:00:00.01 |       4 |       |       |          |
|   2 |   NESTED LOOPS               |       |      1 |    100 |    41 |     7   (0)| 00:00:01 |      0 |00:00:00.01 |       4 |       |       |          |
|*  3 |    HASH JOIN                 |       |      1 |      1 |     7 |     6   (0)| 00:00:01 |      0 |00:00:00.01 |       4 |  2440K|  2440K| 1333K (0)|
|   4 |     TABLE ACCESS FULL        | T3    |      1 |     10 |    30 |     3   (0)| 00:00:01 |     10 |00:00:00.01 |       2 |       |       |          |
|   5 |     TABLE ACCESS FULL        | T4    |      1 |    100 |   400 |     3   (0)| 00:00:01 |    100 |00:00:00.01 |       2 |       |       |          |
|*  6 |    INDEX RANGE SCAN          | T5_I1 |      0 |    100 |       |     1   (0)| 00:00:01 |      0 |00:00:00.01 |       0 |       |       |          |
|   7 |   TABLE ACCESS BY INDEX ROWID| T5    |      0 |      1 |    34 |     1   (0)| 00:00:01 |      0 |00:00:00.01 |       0 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1
   4 - SEL$1 / T3@SEL$1
   5 - SEL$1 / T4@SEL$1
   6 - SEL$1 / T5@SEL$1
   7 - SEL$1 / T5@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("T3"."C1"="T4"."C1")
   6 - access("T4"."C1"="T5"."C1")
       filter("T3"."C1"="T5"."C1")


--看来以后在优化多表连接sql语句时适当加入多余的条件看看执行计划是否存在变化。也说明oracle的优化器还有许多需要改进的地方。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/267265/viewspace-1981803/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/267265/viewspace-1981803/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值