博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Oracle ——如何读执行计划概述
阅读量:6161 次
发布时间:2019-06-21

本文共 24081 字,大约阅读时间需要 80 分钟。

本文内容

  • 测试数据
  • 演示执行计划
  • 修改记录

 

本文简单介绍如何读一个 SQL 语句的执行计划。

我们觉得 SQL 语句执行得有点慢总是不够的,关键是知道为什么慢,在哪里慢。那么,执行计划会给出很多直观的数据。

 

测试数据


SCOTT 用户的表

查看 SCOTT 用户下所有的表。

SQL> select object_name from all_objects
2  where owner='SCOTT'
3  and object_type='TABLE'
4  /
 
OBJECT_NAME
------------------------------
SALGRADE
EMP
DEPT
BONUS
 
SQL>
SCOTT 用户的索引

查看 SCOTT 用户下所有的索引。

SQL> select object_name from all_objects
2  where owner='SCOTT'
3  and object_type='INDEX'
4  /
 
OBJECT_NAME
------------------------------
PK_EMP
PK_DEPT
 
SQL>

该用户下有四个表,本文主要使用 empdept 表,其中,emp 表的 empno 字段为主键;dept 表的 deptno 字段为主键。这是优化器制定执行计划所能使用的部分信息。

演示前执行 "set autot traceonly" 只显示 SQL 语句的执行计划,不显示语句的执行结果。

 

演示 SQL 语句的执行计划


演示 1 简单选择 emp 表,选择列表包含两个字段 empnoename
SQL> select empno,ename from emp
2  /
 
已选择14行。
 
 
执行计划
----------------------------------------------------------
Plan hash value: 3956160932
 
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |    14 |   140 |     3   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| EMP  |    14 |   140 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------
 
统计信息
----------------------------------------------------------
1  recursive calls
0  db block gets
8  consistent gets
0  physical reads
0  redo size
838  bytes sent via SQL*Net to client
519  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
14  rows processed
 
SQL>

执行计划中,ID 列为执行计划的步骤。执行计划是从底网上看的,也即是从 ID 编号最大的开始;OperationName 列为操作及其操作的对象;RowsBytes 列为操作的数据行及其字节大小;Cost 列为代价,它没有任何度量单位,仅仅是一个值,是根据 CPU 代价和 IO 代价算出来的,用来比较操作;Time 列为流逝时间。如下所示。

另外,看执行计划时,要注意每个步骤的缩进。

  • db block gets - 请求当前块的数量。

当前块就是操作中刚好提取数据块数量,而不是在一致性读的情况下而产生的数据块数量。正常情况下,一个查询提取的块是在查询开始的那个时间点上存在的数据块。当前块是在这个时刻存在的数据块,而不是在这个时间点之前或者之后的数据块数量。

  • consistent gets - 一致性读取数据块的数量。

这是在处理你操作时需要在一致性读的状态上处理数据块的数量。这些块产生的主要原因是因为在查询过程中,其他会话对数据块进行操作,可能对你要查询的数据块进行了修改,但我们查询的是修改之前的块,所以需要对回滚段中数据块的前映像进行查询,以保证数据的一致性。这就产生了一致性读。   

  • physical reads - 从磁盘读取数据块的数量。

其产生的主要原因是:1)高速缓存区不存在这些块;2)全表扫描;3)磁盘排序。Physical Reads 是我们最关心的。如果该值高,说明要从磁盘请求大量数据块到高速缓冲区,存在大量全表扫描,从而影响数据库的性能。因此,通过优化 SQL 语句,如创建索引,来避免语句进行全表扫描。

通过 physical reads、db block gets 和 consistent gets 这三个值,可以得到数据缓冲区命中率,即:

缓冲区命中率 = 1 - (physical reads / (db block gets + consistent gets))。

这是计算整个数据库的缓冲区命中率,也可以计算某个 SQL 语句的缓冲区命中率。

 
演示 2 与演示 1 相比字段列表是三个:empnoenamesal
SQL> select empno,ename,sal from emp
2  /
 
已选择14行。
 
 
执行计划
----------------------------------------------------------
Plan hash value: 3956160932
 
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |    14 |   196 |     3   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| EMP  |    14 |   196 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------
 
统计信息
----------------------------------------------------------
1  recursive calls
0  db block gets
8  consistent gets
0  physical reads
0  redo size
951  bytes sent via SQL*Net to client
519  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
14  rows processed
 
SQL>

从执行计划看,与演示 1 相比,只是选择列表多了一个字段,所以 Bytes 列比演示 1 大。

 
演示 3 选择并按 empno 字段倒序排序。选择列表两个字段:empno 和 ename
SQL> select empno,ename from emp order by empno desc
2  /
 
已选择14行。
 
 
执行计划
----------------------------------------------------------
Plan hash value: 3088625055
 
--------------------------------------------------------------------------------------
| Id  | Operation                   | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |        |    14 |   140 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| EMP    |    14 |   140 |     2   (0)| 00:00:01 |
|   2 |   INDEX FULL SCAN DESCENDING| PK_EMP |    14 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------
 
统计信息
----------------------------------------------------------
1  recursive calls
0  db block gets
4  consistent gets
0  physical reads
0  redo size
838  bytes sent via SQL*Net to client
519  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
14  rows processed
 
SQL>

因为该 SQL 语句存在排序,而且排序的字段是表的主键,所以 ID 为 2 的步骤,Operation 列为降序的索引全表扫描,而且 Name 列为 PK_EMP

 
演示 4 选择并按 ename 字段升序排序,但是没有为 ename 字段建立任何索引
SQL> select empno,ename from emp order by ename
2  /
 
已选择14行。
 
 
执行计划
----------------------------------------------------------
Plan hash value: 150391907
 
---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    14 |   140 |     4  (25)| 00:00:01 |
|   1 |  SORT ORDER BY     |      |    14 |   140 |     4  (25)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| EMP  |    14 |   140 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------
 
统计信息
----------------------------------------------------------
1  recursive calls
0  db block gets
7  consistent gets
0  physical reads
0  redo size
838  bytes sent via SQL*Net to client
519  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
1  sorts (memory)
0  sorts (disk)
14  rows processed
 
SQL>

执行计划中,因为 ename 列没有任何索引,所以 ID 为 2 的步骤,Operation 列为全表访问。

 
演示 5 选择工资大于 3000 的员工,选择列表包含两个字段:empno 和 ename
SQL> select empno,ename from emp
2  where sal > 3000
3  /
 
 
执行计划
----------------------------------------------------------
Plan hash value: 3956160932
 
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     7 |    98 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| EMP  |     7 |    98 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("SAL">3000)
 
 
统计信息
----------------------------------------------------------
1  recursive calls
0  db block gets
8  consistent gets
0  physical reads
0  redo size
597  bytes sent via SQL*Net to client
519  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
1  rows processed
 
SQL>

该 SQL 语句与前面的语句相比,多了 WHERE 子句。所以执行计划最后包含了谓词信息。

从执行计划看,ID 为 1 的步骤,利用全表扫描,过滤 SAL > 3000 的数据行。之所以用了全表扫描,是因为 SAL 字段没有任何相关的索引可以利用。

 
演示 6 选择工资最高的前三个人
SQL> select empno,ename from emp
2  where rownum <= 3
3  order by sal desc
4  /
 
 
执行计划
----------------------------------------------------------
Plan hash value: 691404987
 
----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |     3 |    42 |     4  (25)| 00:00:01 |
|   1 |  SORT ORDER BY      |      |     3 |    42 |     4  (25)| 00:00:01 |
|*  2 |   COUNT STOPKEY     |      |       |       |            |          |
|   3 |    TABLE ACCESS FULL| EMP  |    14 |   196 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(ROWNUM<=3)
 
 
统计信息
----------------------------------------------------------
1  recursive calls
0  db block gets
7  consistent gets
0  physical reads
0  redo size
673  bytes sent via SQL*Net to client
519  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
1  sorts (memory)
0  sorts (disk)
3  rows processed
 
SQL>

执行计划中值得注意的是,ID 为 2 的步骤,这是 Oracle 为 TOP n 专门做的优化。

 
演示 7 左连接 emp 和 dept 表
SQL> select a.empno,a.ename,b.dname from emp a
2  left join dept b on(a.deptno=b.deptno)
3  /
 
已选择14行。
 
 
执行计划
----------------------------------------------------------
Plan hash value: 3387915970
 
---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    14 |   364 |     7  (15)| 00:00:01 |
|*  1 |  HASH JOIN OUTER   |      |    14 |   364 |     7  (15)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| EMP  |    14 |   182 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| DEPT |     4 |    52 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("A"."DEPTNO"="B"."DEPTNO"(+))
 
 
统计信息
----------------------------------------------------------
1  recursive calls
0  db block gets
15  consistent gets
0  physical reads
0  redo size
942  bytes sent via SQL*Net to client
519  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
14  rows processed
 
SQL>

我们知道,该语句 JOIN 子句可以转换成 WHERE 子句。这体现在了执行计划后面的谓词条件。ID 为 2 和 3 的步骤,对 emp 和 dept 表都进行了全表扫描。之后进行了哈希连接。

 
演示 8 左连接 emp 和 dept 表,选择工资最高的前三个人,选择列表包含三个字段:empno、ename 和 dname
SQL> select a.empno,a.ename,b.dname from emp a
2  left join dept b on(a.deptno=b.deptno)
3  where rownum <= 3
4  order by a.sal desc
5  /
 
 
执行计划
----------------------------------------------------------
Plan hash value: 3599776420
 
-----------------------------------------------------------------------------
| Id  | Operation            | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |     3 |    90 |     8  (25)| 00:00:01 |
|   1 |  SORT ORDER BY       |      |     3 |    90 |     8  (25)| 00:00:01 |
|*  2 |   COUNT STOPKEY      |      |       |       |            |          |
|*  3 |    HASH JOIN OUTER   |      |    14 |   420 |     7  (15)| 00:00:01 |
|   4 |     TABLE ACCESS FULL| EMP  |    14 |   238 |     3   (0)| 00:00:01 |
|   5 |     TABLE ACCESS FULL| DEPT |     4 |    52 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(ROWNUM<=3)
3 - access("A"."DEPTNO"="B"."DEPTNO"(+))
 
 
统计信息
----------------------------------------------------------
1  recursive calls
0  db block gets
14  consistent gets
0  physical reads
0  redo size
763  bytes sent via SQL*Net to client
519  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
1  sorts (memory)
0  sorts (disk)
3  rows processed
 
SQL>

执行计划中,除了能看到演示 7 所体现的,还能 TOP n 操作的计划。

    • Access - 访问谓词会影响访问路径,是全表扫描,还是索引扫描。
    • Filter - 过滤谓词不会影响访问路劲,只起过滤的作用。
 
演示 9 演示 8 等值连接
SQL> select a.empno,a.ename,b.dname from emp a, dept b
2  where a.deptno=b.deptno
3  and rownum <= 3
4  order by a.sal desc
5  /
 
 
执行计划
----------------------------------------------------------
Plan hash value: 4235606028
 
------------------------------------------------------------------------------------------
| Id  | Operation                      | Name    | Rows  | Bytes | Cost (%CPU)|Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |         |     3 |    90 |     7  (29)|00:00:01 |
|   1 |  SORT ORDER BY                 |         |     3 |    90 |     7  (29)|00:00:01 |
|*  2 |   COUNT STOPKEY                |         |       |       |            |         |
|   3 |    MERGE JOIN                  |         |    14 |   420 |     6  (17)|00:00:01 |
|   4 |     TABLE ACCESS BY INDEX ROWID| DEPT    |     4 |    52 |     2   (0)|00:00:01 |
|   5 |      INDEX FULL SCAN           | PK_DEPT |     4 |       |     1   (0)|00:00:01 |
|*  6 |     SORT JOIN                  |         |    14 |   238 |     4  (25)|00:00:01 |
|   7 |      TABLE ACCESS FULL         | EMP     |    14 |   238 |     3   (0)|00:00:01 |
------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(ROWNUM<=3)
6 - access("A"."DEPTNO"="B"."DEPTNO")
filter("A"."DEPTNO"="B"."DEPTNO")
 
 
统计信息
----------------------------------------------------------
1  recursive calls
0  db block gets
9  consistent gets
0  physical reads
0  redo size
763  bytes sent via SQL*Net to client
519  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
2  sorts (memory)
0  sorts (disk)
3  rows processed
 
SQL>

以上演示都是 SCOTT 用户下默认的对象,包括表和索引。下面自己创建一些索引,看看执行计划如何。

 
演示 10 为 sal 字段创建索引,并再次执行演示 5
SQL> create index emp_sal_idx on emp(sal)
2  /
 
索引已创建。
 
SQL> select empno,ename from emp
2  where sal > 3000
3  /
 
 
执行计划
----------------------------------------------------------
Plan hash value: 3428524353
 
--------------------------------------------------------------------------------
-----------
| Id  | Operation                   | Name        | Rows  | Bytes | Cost (%CPU)|
 
Time     |
 
--------------------------------------------------------------------------------
-----------
|   0 | SELECT STATEMENT            |             |     7 |    98 |     2   (0)|
 
00:00:01 |
 
|   1 |  TABLE ACCESS BY INDEX ROWID| EMP         |     7 |    98 |     2   (0)|
 
00:00:01 |
 
|*  2 |   INDEX RANGE SCAN          | EMP_SAL_IDX |     7 |       |     1   (0)|
 
00:00:01 |
 
--------------------------------------------------------------------------------
-----------
 
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("SAL">3000)
 
 
统计信息
----------------------------------------------------------
1  recursive calls
0  db block gets
2  consistent gets
0  physical reads
0  redo size
597  bytes sent via SQL*Net to client
519  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
1  rows processed
 
SQL>

执行计划显示,使用了刚才创建的 emp_sal_idx 索引。不再是全表扫描。

 
演示 11 部门为 30,并且工资在 1500 到 2900 所有员工
SQL> select t1.empno,t1.ename,t1.sal,t2.dname from emp t1,dept t2
2  where t1.deptno=t2.deptno
3  and t2.deptno=30 and t1.sal between 1500 and 2900
4  /
 
 
执行计划
----------------------------------------------------------
Plan hash value: 568005898
 
----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |     2 |    60 |     4   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                |         |     2 |    60 |     4   (0)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    13 |     1   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | PK_DEPT |     1 |       |     0   (0)| 00:00:01 |
|*  4 |   TABLE ACCESS FULL          | EMP     |     2 |    34 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("T2"."DEPTNO"=30)
4 - filter("T1"."DEPTNO"=30 AND "T1"."SAL"<=2900 AND "T1"."SAL">=1500)
 
 
统计信息
----------------------------------------------------------
1  recursive calls
0  db block gets
10  consistent gets
0  physical reads
0  redo size
682  bytes sent via SQL*Net to client
416  bytes received via SQL*Net from client
4  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
3  rows processed
 
SQL>

执行计划中,emp 表使用了全表扫描,因为目前只对 SAL 字段创建了索引,而过滤谓词中,不仅包含 emp 表的 SAL 字段,还包含 dept 表的 DEPTNO 字段。

 
演示 12 与演示 11 类似,唯一不同的是 WHERE 子句中条件 deptno,使用的是 emp 表,而不是 dept 表
SQL> select t1.empno,t1.ename,t1.sal,t2.dname from emp t1,dept t2
2  where t1.deptno=t2.deptno
3  and t1.deptno=30 and t1.sal between 1500 and 2900
4  /
 
 
执行计划
----------------------------------------------------------
Plan hash value: 568005898
 
----------------------------------------------------------------------------------------
| Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |         |     2 |    60 |     4   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                |         |     2 |    60 |     4   (0)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    13 |     1   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | PK_DEPT |     1 |       |     0   (0)| 00:00:01 |
|*  4 |   TABLE ACCESS FULL          | EMP     |     2 |    34 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("T2"."DEPTNO"=30)
4 - filter("T1"."DEPTNO"=30 AND "T1"."SAL"<=2900 AND "T1"."SAL">=1500)
 
 
统计信息
----------------------------------------------------------
1  recursive calls
0  db block gets
10  consistent gets
0  physical reads
0  redo size
682  bytes sent via SQL*Net to client
416  bytes received via SQL*Net from client
4  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
3  rows processed
 
SQL>

执行计划与演示 11 相同。对 EMP 表仍然使用了全表扫描。

 
演示 13 为 EMP 表的 deptno 和 sal 字段创建组合索引,执行与演示 12 相同的操作
SQL> create index emp_deptno_sal_idx on emp(deptno,sal)
2  /
 
索引已创建。
 
SQL> select t1.empno,t1.ename,t1.sal,t2.dname from emp t1,dept t2
2  where t1.deptno=t2.deptno
3  and t1.deptno=30 and t1.sal between 1500 and 2900
4  /
 
 
执行计划
----------------------------------------------------------
Plan hash value: 668448259
 
-----------------------------------------------------------------------------------------------
| Id  | Operation                    | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                |     2 |    60 |        3(0)| 00:00:01 |
|   1 |  NESTED LOOPS                |                |     2 |    60 |        3(0)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| DEPT           |     1 |    13 |        1(0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | PK_DEPT        |     1 |       |        0(0)| 00:00:01 |
|   4 |   TABLE ACCESS BY INDEX ROWID| EMP            |     2 |    34 |        2(0)| 00:00:01 |
|*  5 |    INDEX RANGE SCAN          | EMP_DEPTNO_SAL |     2 |       |        1(0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("T2"."DEPTNO"=30)
5 - access("T1"."DEPTNO"=30 AND "T1"."SAL">=1500 AND "T1"."SAL"<=2900)
 
 
统计信息
----------------------------------------------------------
1  recursive calls
0  db block gets
6  consistent gets
0  physical reads
0  redo size
682  bytes sent via SQL*Net to client
416  bytes received via SQL*Net from client
4  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
3  rows processed
 
SQL>

从执行计划看,创建组合索引后,对 EMP 表使用了 EMP_DEPTNO_SAL 索引。

 
演示 14 利用 EMP_DEPTNO_SAL 索引,执行与演示 11 相同的操作
SQL> select t1.empno,t1.ename,t1.sal,t2.dname from emp t1,dept t2
2  where t1.deptno=t2.deptno
3  and t2.deptno=30 and t1.sal between 1500 and 2900
4  /
 
 
执行计划
----------------------------------------------------------
Plan hash value: 1121164890
 
---------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name               | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                    |     2 |    60 |     3   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                |                    |     2 |    60 |     3   (0)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| DEPT               |     1 |    13 |     1   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | PK_DEPT            |     1 |       |     0   (0)| 00:00:01 |
|   4 |   TABLE ACCESS BY INDEX ROWID| EMP                |     2 |    34 |     2   (0)| 00:00:01 |
|*  5 |    INDEX RANGE SCAN          | EMP_DEPTNO_SAL_IDX |     2 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("T2"."DEPTNO"=30)
5 - access("T1"."DEPTNO"=30 AND "T1"."SAL">=1500 AND "T1"."SAL"<=2900)
 
 
统计信息
----------------------------------------------------------
219  recursive calls
0  db block gets
49  consistent gets
0  physical reads
0  redo size
682  bytes sent via SQL*Net to client
416  bytes received via SQL*Net from client
4  SQL*Net roundtrips to/from client
6  sorts (memory)
0  sorts (disk)
3  rows processed
 
SQL>

执行计划中,除了 recursive calls 和 consistent gets 高的出奇外,其他全部一样。归根结底,组合索引 EMP_DEPTNO_SAL 是在 EMP 表上创建,而 SQL 语句的 WHERE 子句中 deptno 字段使用的却是 dept 表。

 
演示 15 统计表,并执行与演示 11 相同的操作
SQL> analyze table emp compute statistics
2  for table
3  for all indexes
4  for all indexed columns
5  /
 
表已分析。
 
SQL> select t1.empno,t1.ename,t1.sal,t2.dname from emp t1,dept t2
2  where t1.deptno=t2.deptno
3  and t2.deptno=30 and t1.sal between 1500 and 2900
4  /
 
 
执行计划
----------------------------------------------------------
Plan hash value: 1121164890
 
---------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name               | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                    |     1 |    27 |     3   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                |                    |     1 |    27 |     3   (0)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| DEPT               |     1 |    13 |     1   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | PK_DEPT            |     1 |       |     0   (0)| 00:00:01 |
|   4 |   TABLE ACCESS BY INDEX ROWID| EMP                |     1 |    14 |     2   (0)| 00:00:01 |
|*  5 |    INDEX RANGE SCAN          | EMP_DEPTNO_SAL_IDX |     1 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("T2"."DEPTNO"=30)
5 - access("T1"."DEPTNO"=30 AND "T1"."SAL">=1500 AND "T1"."SAL"<=2900)
 
 
统计信息
----------------------------------------------------------
1  recursive calls
0  db block gets
6  consistent gets
0  physical reads
0  redo size
682  bytes sent via SQL*Net to client
416  bytes received via SQL*Net from client
4  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
3  rows processed
 
SQL>

此时,执行计划就变得正常了。

 

修改记录


  • 2012-09-17 [UPDATE]

 

o_%E5%8E%9F%E5%88%9B.jpg

转载地址:http://qmhfa.baihongyu.com/

你可能感兴趣的文章
虚机不能启动的特例思考
查看>>
SQL Server编程系列(1):SMO介绍
查看>>
在VMware网络测试“专用VLAN”功能
查看>>
使用Formik轻松开发更高质量的React表单(三)<Formik />解析
查看>>
也问腾讯:你把用户放在什么位置?
查看>>
CSS Sprites 样式生成工具(bg2css)
查看>>
[转]如何重构代码--重构计划
查看>>
类中如何对list泛型做访问器??
查看>>
C++解析XML--使用CMarkup类解析XML
查看>>
P2P应用层组播
查看>>
Sharepoint学习笔记—修改SharePoint的Timeouts (Execution Timeout)
查看>>
CSS引入的方式有哪些? link和@import的区别?
查看>>
Redis 介绍2——常见基本类型
查看>>
asp.net开发mysql注意事项
查看>>
(转)Cortex-M3 (NXP LPC1788)之EEPROM存储器
查看>>
ubuntu set defult jdk
查看>>
[译]ECMAScript.next:TC39 2012年9月会议总结
查看>>
【Xcode】编辑与调试
查看>>
用tar和split将文件分包压缩
查看>>
[BTS] Could not find stored procedure 'mp_sap_check_tid'
查看>>