Oracle开发者性能课第1课(如何阅读执行计划)实验

Posted dingdingfish

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle开发者性能课第1课(如何阅读执行计划)实验相关的知识,希望对你有一定的参考价值。

概述

本实验参考DevGym中的实验指南

创建环境

首先创建表,并在最后搜集统计信息:

create table bricks (
  colour   varchar2(10),
  shape    varchar2(10)
);

create table colours (
  colour        varchar2(10),
  rgb_hex_value varchar2(6)
);

create table cuddly_toys (
  toy_name varchar2(20),
  colour   varchar2(10)
);

create table pens (
  colour   varchar2(10),
  pen_type varchar2(10)
);


insert into cuddly_toys values ( 'Miss Snuggles', 'pink' ) ;
insert into cuddly_toys values ( 'Cuteasaurus', 'blue' ) ;
insert into cuddly_toys values ( 'Baby Turtle', 'green' ) ;
insert into cuddly_toys values ( 'Green Rabbit', 'green' ) ;
insert into cuddly_toys values ( 'White Rabbit', 'white' ) ;

insert into colours values ( 'red' , 'FF0000' ); 
insert into colours values ( 'blue' , '0000FF' ); 
insert into colours values ( 'green' , '00FF00' ); 

insert into bricks values ( 'red', 'cylinder' );
insert into bricks values ( 'blue', 'cube' );
insert into bricks values ( 'green', 'cube' );

insert into bricks
  select * from bricks;
  
insert into bricks
  select * from bricks;
  
insert into bricks
  select * from bricks;

insert into pens values ( 'black', 'ball point' );
insert into pens values ( 'black', 'permanent' );
insert into pens values ( 'blue', 'ball point' );
insert into pens values ( 'green', 'permanent' );
insert into pens values ( 'green', 'dry-wipe' );
insert into pens values ( 'red', 'permanent' );
insert into pens values ( 'red', 'dry-wipe' );
insert into pens values ( 'blue', 'permanent' );
insert into pens values ( 'blue', 'dry-wipe' );

commit;

exec dbms_stats.gather_table_stats ( null, 'pens' ) ;
exec dbms_stats.gather_table_stats ( null, 'colours' ) ;
exec dbms_stats.gather_table_stats ( null, 'bricks' ) ;
exec dbms_stats.gather_table_stats ( null, 'cuddly_toys' ) ;

查看数据,总共4个表:

SQL> select * from bricks;

   COLOUR       SHAPE
_________ ___________
red       cylinder
blue      cube
green     cube
red       cylinder
blue      cube
green     cube
red       cylinder
blue      cube
green     cube
red       cylinder
blue      cube
green     cube
red       cylinder
blue      cube
green     cube
red       cylinder
blue      cube
green     cube
red       cylinder
blue      cube
green     cube
red       cylinder
blue      cube
green     cube

24 rows selected.

SQL> select * from colours;
   COLOUR    RGB_HEX_VALUE
_________ ________________
red       FF0000
blue      0000FF
green     00FF00


SQL> select * from cuddly_toys;
        TOY_NAME    COLOUR
________________ _________
Miss Snuggles    pink
Cuteasaurus      blue
Baby Turtle      green
Green Rabbit     green
White Rabbit     white


SQL> select * from pens;
   COLOUR      PEN_TYPE
_________ _____________
black     ball point
black     permanent
blue      ball point
green     permanent
green     dry-wipe
red       permanent
red       dry-wipe
blue      permanent
blue      dry-wipe

9 rows selected.

DBMS_XPLAN获取执行计划

推荐看一下How to Create an Execution Plan

推荐方法是使用DBMS_XPLAN,下例是获取最近一个SQL的执行计划。

SQL> select *
  2  from   bricks b
  3  join   colours c
  4  on     b.colour = c.colour;

   COLOUR       SHAPE    COLOUR    RGB_HEX_VALUE
_________ ___________ _________ ________________
red       cylinder    red       FF0000
blue      cube        blue      0000FF
green     cube        green     00FF00
red       cylinder    red       FF0000
blue      cube        blue      0000FF
green     cube        green     00FF00
red       cylinder    red       FF0000
blue      cube        blue      0000FF
green     cube        green     00FF00
red       cylinder    red       FF0000
blue      cube        blue      0000FF
green     cube        green     00FF00
red       cylinder    red       FF0000
blue      cube        blue      0000FF
green     cube        green     00FF00
red       cylinder    red       FF0000
blue      cube        blue      0000FF
green     cube        green     00FF00
red       cylinder    red       FF0000
blue      cube        blue      0000FF
green     cube        green     00FF00
red       cylinder    red       FF0000
blue      cube        blue      0000FF
green     cube        green     00FF00

24 rows selected.

SQL> select * from table(dbms_xplan.display_cursor());

                                                                PLAN_TABLE_OUTPUT
_________________________________________________________________________________
SQL_ID  bhrapfvbrag71, child number 0
-------------------------------------
select * from   bricks b join   colours c on     b.colour = c.colour

Plan hash value: 2784388402

------------------------------------------------------------------------------
| Id  | Operation          | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |         |       |       |     6 (100)|          |
|*  1 |  HASH JOIN         |         |    24 |   552 |     6   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| COLOURS |     3 |    36 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| BRICKS  |    24 |   264 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("B"."COLOUR"="C"."COLOUR")


20 rows selected.

查找SQL语句的SQL ID

SQL_ID为13字节,是SQL文本的哈希值。所以SQL不变,SQL_ID不变;哪怕SQL中加入了注释,SQL_ID也会变。

SQL> select sql_id, sql_text
  2  from   v$sql
  3  where  sql_text like 'select *%bricks b%'
  4  ;

          SQL_ID                                                                SQL_TEXT
________________ _______________________________________________________________________
bhrapfvbrag71    select * from   bricks b join   colours c on     b.colour = c.colour

在DBMS_XPLAN中使用SQL_ID

这样就可以查看其它会话或之前的SQL的执行计划:

SQL> select *
  2  from   table(dbms_xplan.display_cursor('bhrapfvbrag71'));

                                                                PLAN_TABLE_OUTPUT
_________________________________________________________________________________
SQL_ID  bhrapfvbrag71, child number 0
-------------------------------------
select * from   bricks b join   colours c on     b.colour = c.colour

Plan hash value: 2784388402

------------------------------------------------------------------------------
| Id  | Operation          | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |         |       |       |     6 (100)|          |
|*  1 |  HASH JOIN         |         |    24 |   552 |     6   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| COLOURS |     3 |    36 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| BRICKS  |    24 |   264 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("B"."COLOUR"="C"."COLOUR")


20 rows selected.

如果不知道SQL_ID,也可以通过SQL文本查找:

select /* colours query */* from colours;

select p.*  
from   v$sql s, table (  
  dbms_xplan.display_cursor (  
    s.sql_id, s.child_number, 'BASIC'  
  )  
) p  
where s.sql_text like '%colours query%'  /* enter text from the target statement here */
and   s.sql_text not like '%not this%';

如何阅读执行计划

不赘述了,推荐How to Read an Execution Plan

核心规则就是:

To follow an execution plan, the database uses a depth-first search, which starts from the top of the plan and works down the tree to the first leaf. It then walks back up the tree to the first operation with an unvisited child.

使用深度优先搜索,从执行计划的顶部开始,沿着树一直向下搜索到第一个叶子节点。 然后回到父节点下面下一个未访问过的子节点。

执行计划解读示例1

select c.*, pen_type, shape, toy_name 
from   colours c
join   pens p
on     c.colour = p.colour
join   cuddly_toys t
on     c.colour = t.colour
join   bricks b
on     c.colour = b.colour;

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

                                                                      PLAN_TABLE_OUTPUT
_______________________________________________________________________________________
SQL_ID  gdk2sd4huxr83, child number 0
-------------------------------------
select c.*, pen_type, shape, toy_name  from   colours c join   pens p
on     c.colour = p.colour join   cuddly_toys t on     c.colour =
t.colour join   bricks b on     c.colour = b.colour

Plan hash value: 1245878025

------------------------------------------------------------------------------------
| Id  | Operation            | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |             |       |       |    12 (100)|          |
|*  1 |  HASH JOIN           |             |    68 |  3876 |    12   (0)| 00:00:01 |
|*  2 |   HASH JOIN          |             |     8 |   368 |     9   (0)| 00:00:01 |
|*  3 |    HASH JOIN         |             |     4 |   124 |     6   (0)| 00:00:01 |
|   4 |     TABLE ACCESS FULL| COLOURS     |     3 |    36 |     3   (0)| 00:00:01 |
|   5 |     TABLE ACCESS FULL| CUDDLY_TOYS |     5 |    95 |     3   (0)| 00:00:01 |
|   6 |    TABLE ACCESS FULL | PENS        |     9 |   135 |     3   (0)| 00:00:01 |
|   7 |   TABLE ACCESS FULL  | BRICKS      |    24 |   264 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("C"."COLOUR"="B"."COLOUR")
   2 - access("C"."COLOUR"="P"."COLOUR")
   3 - access("C"."COLOUR"="T"."COLOUR")


28 rows selected.

执行顺序为:4,3,5,3,2,6,2,1,7,1,0。

执行计划解读示例2

select c.colour, count(*)
from   colours c 
join   (
  select colour, shape from bricks
  union all
  select colour, toy_name from cuddly_toys
  union all
  select colour, pen_type from pens
) t
on     t.colour = c.colour
group  by c.colour;

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

                                                                       PLAN_TABLE_OUTPUT
________________________________________________________________________________________
SQL_ID  2c2x0ux1k106c, child number 0
-------------------------------------
select c.colour, count(*) from   colours c  join   (   select colour,
shape from bricks   union all   select colour, toy_name from
cuddly_toys   union all   select colour, pen_type from pens ) t on
t.colour = c.colour group  by c.colour

Plan hash value: 1792629648

-------------------------------------------------------------------------------------
| Id  | Operation             | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |             |       |       |    13 (100)|          |
|   1 |  HASH GROUP BY        |             |     3 |    33 |    13   (8)| 00:00:01 |
|*  2 |   HASH JOIN           |             |    23 |   253 |    12   (0)| 00:00:01 |
|   3 |    TABLE ACCESS FULL  | COLOURS     |     3 |    15 |     3   (0)| 00:00:01 |
|   4 |    VIEW               |             |    38 |   228 |     9   (0)| 00:00:01 |
|   5 |     UNION-ALL         |             |       |       |            |          |
|   6 |      TABLE ACCESS FULL| BRICKS      |    24 |   120 |     3   (0)| 00:00:01 |
|   7 |      TABLE ACCESS FULL| CUDDLY_TOYS |     5 |    30 |     3   (0)| 00:00:01 |
|   8 |      TABLE ACCESS FULL| PENS        |     9 |    54 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("T"."COLOUR"="C"."COLOUR")


28 rows selected.

执行顺序为:3,2,6,7,8,5,2,1,0

查看执行计划中处理的行数

通过format参数可指定许多选项。

select *
from   bricks b
join   colours c
on     b.colour = c.colour;

select * 
from   table(dbms_xplan.display_cursor(:LIVESQL_LAST_SQL_ID, format => 'ROWSTATS LAST'));

                                                      PLAN_TABLE_OUTPUT
_______________________________________________________________________
SQL_ID  bhrapfvbrag71, child number 1
-------------------------------------
select * from   bricks b join   colours c on     b.colour = c.colour

Plan hash value: 2784388402

-----------------------------------------------------------------
| Id  | Operation          | Name    | Starts | E-Rows | A-Rows |
-----------------------------------------------------------------
|   0 | SELECT STATEMENT   |         |      1 |        |     24 |
|*  1 |  HASH JOIN         |         |      1 |     24 |     24 |
|   2 |   TABLE ACCESS FULL| COLOURS |      1 |      3 |      3 |
|   3 |   TABLE ACCESS FULL| BRICKS  |      1 |     24 |     24 |
-----------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("B"."COLOUR"="C"."COLOUR")


20 rows selected.

要获得基本执行计划之外的统计信息,需要以下两个条件之一:

  1. SQL中有提示/*+ gather_plan_statistics */
  2. alter session set statistics_level = all

否则会有如下的警告,并且有信息缺失:

                                                                   PLAN_TABLE_OUTPUT
____________________________________________________________________________________
SQL_ID  bhrapfvbrag71, child number 0
-------------------------------------
以上是关于Oracle开发者性能课第1课(如何阅读执行计划)实验的主要内容,如果未能解决你的问题,请参考以下文章

Oracle开发者性能课第6课(如何创建物化视图)实验

Oracle开发者性能课第4课(如何创建索引)实验

Oracle开发者性能课第9课(如何查找慢 SQL)实验

Oracle开发者性能课第8课(如何更快地进行插入更新和删除)实验

Oracle开发者性能课第3课(我的查询做了多少工作)实验

Oracle开发者性能课第5课(为什么我的查询不使用索引)实验