2 第一篇 执 - baidu

14
第一篇 行计划是指示 Oracle 如何获取和过滤数据产生最终结果集是影响 SQL 语句执 行性能的关键因素我们在深入了解执行计划之前首先需要知道执行计划是在 什么时候产生的以及如何让 SQL 引擎为语句生成执行计划在深入了解执行计划之前我们先了解 SQL 语句的处理执行过程当一条语句提交到 Oracle SQL 引擎会分为三个步骤对其处理和执行 解析Parse)、执行Execute和获 Fetch),分别由 SQL 引擎的不同组件完成SQL 引擎的组件如图 1-1 所示1. SQL 编译器SQL Compiler将语句编译到一个共享游标中SQL 编译器由解析器Parser)、 查询优化器Query Optimizer和行源生成器Row Source Generator组成解析器Parser执行对 SQL 语句的语法语义分析将查询中的视图展开分为小的查询块查询优化器Query Optimizer为语句生成一组可能被使用的执行计划估算 出每个执行计划的代价并调用计划生成器Plan Generator生成计划比较计 划的代价最终选择选择一个代价最小的计划查询优化器由查询转换器Query Transform)、代价估算器Estimator和计划生成器Plan Generator组成注意上述优化器实际上指的是基于代价的优化器Cost Based OptimizerCBO), CBO 也是当前采用的所有优化和调优技术的核心基础

Upload: others

Post on 15-Oct-2021

29 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 2 第一篇 执 - Baidu

第一篇

执 行 计 划

执行计划是指示 Oracle 如何获取和过滤数据、产生最终结果集,是影响 SQL 语句执

行性能的关键因素。我们在深入了解执行计划之前,首先需要知道执行计划是在

什么时候产生的,以及如何让 SQL 引擎为语句生成执行计划。

在深入了解执行计划之前,我们先了解 SQL 语句的处理执行过程。当一条语句提交到

Oracle 后,SQL 引擎会分为三个步骤对其处理和执行:解析(Parse)、执行(Execute)和获

取(Fetch),分别由 SQL 引擎的不同组件完成。SQL 引擎的组件如图 1-1 所示。

1. SQL 编译器(SQL Compiler)将语句编译到一个共享游标中。SQL 编译器由解析器(Parser)、查询优化器(Query

Optimizer)和行源生成器(Row Source Generator)组成。

❑ 解析器(Parser)—执行对 SQL 语句的语法、语义分析,将查询中的视图展开、划

分为小的查询块。

❑ 查询优化器(Query Optimizer)—为语句生成一组可能被使用的执行计划,估算

出每个执行计划的代价,并调用计划生成器(Plan Generator)生成计划,比较计

划的代价,最终选择选择一个代价最小的计划。查询优化器由查询转换器(Query Transform)、代价估算器(Estimator)和计划生成器(Plan Generator)组成。

注意,上述优化器实际上指的是基于代价的优化器(Cost Based Optimizer,CBO),

CBO 也是当前采用的所有优化和调优技术的核心基础。

Page 2: 2 第一篇 执 - Baidu

2   第一篇 执 行 计 划

解析器

SQL 编译器

对 SQL 语句的语法、语义分析,将查询中的视图展开、划分为小的查询块

查询优化器

查询转换器 代价估算器 计划生成器

行源生成器

为执行计划生成行源

SQL 执行引擎

按照语句的执行计划进行操作,产生查询结果

图 1-1 SQL 引擎结构及其组件示意图

查询转换器(Query Transformer)—查询转换器决定是否重写用户的查询(包括视图

合并、子查询反嵌套),以生成更好的查询计划。

代价估算器(Estimator)—代价估算器使用统计数据来估算操作的选择率(Selectivity)、返回数据集的势(Cardinality)和代价,并最终估算出整个执行计划的代价。

计划生成器(Plan Generator)—计划生成器会考虑可能的访问路径(Access Path)、关联方法和关联顺序,生成不同的执行计划,让查询优化器从这些计划中选择出代价最小的

一个计划。

❑ 行源生成器(Row Source Generator)—行源生成器从优化器接收到优化的执行计

划后,为该计划生成行源(Row Source)。行源是一个可被迭代控制的结构体,它能以迭代

方式处理一组数据行、并生成一组数据行。

2. SQL 执行引擎(SQL Execution Engine)SQL 执行引擎依照语句的执行计划进行操作,产生查询结果。在每一个操作中,SQL 执

行引擎会以迭代方式执行行源、生成数据行。

提示 :当 Oracle 引入一些新的优化技术时,会出现一些新的组件,例如,SQL 进化管

理器(SPM)、SQL 性能分析器(SPA)等,这些组件会与 SQL 引擎的组件融合,提供更好

的优化和调优方法。

Page 3: 2 第一篇 执 - Baidu

第 1 章 生成和显示执行计划

任何一条 SQL 语句要正确运行并返回结果,SQL 执行引擎都必须获得一个相应的执行

计划。当缓存当中找不到与当前环境相匹配的执行计划时,SQL 编译器会解析和生成

一个相应的执行计划。已经生成的执行计划会驻留在缓存当中,直至其失效或者被清出缓存。

如果想要生成和显示一条语句的执行计划,方法有多种。大致上分为两类 :从内存或者

历史数据中读取曾经执行语句的执行计划;使用 Explain Plan 命令解析语句后,从表 PLAN_TABLE 获得生成的执行计划。

在本章中,我们将会了解到以下内容:

❑ 在 Oracle 中,SQL 语句如何生成执行计划。

❑ 如何获取和显示 SQL 语句的执行计划。

1.1 生成执行计划

在 Oracle 中,任何一条语句在解析过程中都会生成一个唯一的数值标识,即 SQL_ID。

而同一条语句,在解析过程中,可能会因为执行环境的改变(例如某些优化参数被改变)而

生成多个版本的游标,不同的游标会有不同的执行计划。每个游标都会按顺序赋予一个序列

号,即 CHILD_NUMBER,一条语句生成的第一个游标的 CHILD_NUMBER 为 0 ;相应的,

Oracle 会为每个执行计划生成一个哈希值以作区分。而多个不同版本的游标,其执行计划可

能会相同,也可能不同。

因此,我们可以知道,一条合法的 SQL 语句在执行过后,在内存中最少会有一个执行

计划与其游标相对应。当前实例内存(Library Cache)中的执行计划可以通过视图 V$SQL_PLAN 读取(RAC 环境中,可以通过视图 gv$sql_plan 查看 RAC 当中其他实例上的执行计

划)。在启用了自动负载知识库(Automatic Workload Repository,AWR,10g 及以后版本),

Oracle 会将内存中的执行计划存储在历史数据当中,我们可以通过查询语句或者 Oracle 提供

的包 DBMS_XPLAN 从历史数据中读取。此外,从 10g 开始,Oracle 还提供一个自动优化

工具 DBMS_SQLTUNE 对单个或一组语句进行自动优化,它可以在一段时间内捕捉内存中

语句和执行计划来生成一组 SQL 集(或者称 SQL 调优集,SQL Tuning Set),我们同样可以

从 SQL 集中读取和显示语句的执行计划。在 11g 当中,Oracle 又引入了 SQL 执行计划管理

(SQL Plan Management)的特性,可以将语句的一个或多个执行计划存储在一个执行计划基

线(Plan Baseline)当中,我们同样可以读取基于执行计划基线生成的计划。

提示:AWR 的历史数据、执行计划基线都是有保存期限的,可以通过相关参数设置。

除了通过执行 SQL 让 Oracle 处理引擎在内存中生成执行计划外,我们还可以通过命令

Explain Plan 让优化器仅对 SQL 语句进行解释,生成查询计划。由于语句并不会实际执行,

Page 4: 2 第一篇 执 - Baidu

4   第一篇 执 行 计 划

因此它可以含有没有赋值的绑定变量。

执行 Explain Plan 命令后,Oracle 会将解释生成的查询计划插入表 SYS.PLAN_TABLE$(10g之前,表名为 PLAN_TABLE ;10g 之后,通过公共同义词 PLAN_TABLE 指向 SYS.PLAN_TABLE$)中。我们就可以通过查询语句或者 Oracle 提供的包 DBMS_XPLAN 从该表中读取查

询计划。注意,通过 Explain Plan 解释出来的查询计划不会被缓存到内存中以便在语句执行

时重用,我们在缓存当中看到的是类似“explain plan for <SQL>”的形式。

要注意的是,如果要解析语句的执行计划,用户必须拥有语句中对象及其依赖对象的权

限。如果语句中存在视图,用户必须有对视图依赖表的查询权限。例如,当一个用户 A 基于

表 T 创建了一个视图 V,并将视图的查询权限赋予了用户 B,那么用户 B 仅能通过视图查询

表的数据,但无法直接调用 Explain Plan 命令解析基于该视图的查询的执行计划。

1.2 显示执行计划

我们现在知道,有三个途径可以获取查询计划 :v$sql_plan、dba_hist_sql_plan 和 PLAN_TABLE。如果需要读取一条 SQL 语句的执行计划,就需要知道该条语句的 SQL_ID,如果该

语句存在多个游标或者执行计划,则还需要知道游标的 CHILD_NUMBER 或计划的哈希值

(可选)。而无论我们通过哪个途径来获取执行计划,显示方式主要是两种 :语句查询和包

DBMS_XPLAN 显示。

1.2.1 通过查询语句显示计划

通过查询语句从一些视图里读出执行计划并作格式化输出的方法都非常相似,这里以

v$sql_plan 视图为例,示例程序见代码清单 1-1。

代码清单 1-1 显示执行计划(查询语句)

HELLODBA.COM>col "Query Plan_Table" format a30

-- 提示:SQL_ID可以从视图v$sql_text和 dba_hist_sqltext(或 stats$sqltext)等视图中查询获得。

HELLODBA.COM>select id,lpad(' ', 2*(level-1))||operation||' '||options||' '||

2 object_name||' '||decode(id, 0, 'Cost='||cost) "Query Plan_Table"

3 from v$sql_plan

4 start with id = 0

5 and sql_id = 'dq7gjn1yrpcyz'

6 and plan_hash_value = 616708042

7 connect by prior id = parent_id

8 and sql_id = 'dq7gjn1yrpcyz'

9 and plan_hash_value = 616708042;

ID Query Plan_Table

---------- ------------------------------

0 SELECT STATEMENT Cost=2

1 TABLE ACCESS FULL T_USERS

1.2.2 通过包 DBMS_XPLAN 显示计划

这个包可以根据我们选择的函数以及输入的参数来格式化显示相关的执行计划,在我们

Page 5: 2 第一篇 执 - Baidu

第 1 章 生成和显示执行计划   5

随后的内容中,主要会使用(也推荐读者使用)该工具显示执行计划。

DBMS_XPLAN 含有 5 个函数用于输出格式化的执行计划,display、display_cursor、display_awr、display_sqlset 和 display_sql_plan_baseline,分别用于显示 Explain Plan 命令

解释的计划、内存中的执行计划、AWR 历史数据中的计划、SQL 优化集中语句的计划、执

行计划基线(关于 SQL 优化集和执行计划基线,我们会在后面第 7 章中具体介绍)。它们都

是管道化表函数(Pipelined Table Function),返回的结果是一个系统自定义的集合数据类型

dbms_xplan_type_table。我们可以通过表函数(Table)进行映射后进行查询。

1.2.2.1 DISPLAYDISPLAY 函数用于显示存储在 PLAN_TABLE 中的执行计划,或与 PLAN_TABLE 拥有

相同结构的表中的执行计划。此外,如果从视图 v$sql_plan_statistics_all 可以获得该执行计

划的相关统计数据,DISPLAY 也可以格式化输出这些数据。

参数描述:

❑ TABLE_NAME:存储查询计划的表名(不区分大小写),默认值为 PLAN_TABLE。❑ STATEMENT_ID :SQL 语句 ID。在 PLAN_TABLE 中,每条语句的执行计划都会有

一个唯一的 ID 来标识。这个 ID 可以在执行 Explain Plan 命令时,通过 Set Statement_id 子句来指定。如果输入为 NULL,则会获取最近一条被解释的语句。

❑ FORMAT:输出格式。在 DISPLAY 函数中,有以下预定义的格式(模板)可供选择:

❍ 'BASIC' :基本格式。输出的内容最少,仅仅输出查询计划中每个操作的 ID、名称

和选项以及操作的对象名。

❍ 'TYPICAL' :典型格式。输出的内容是我们进行语句调优时大多数情况下所需要的

信息。除了基本格式中的内容外,还会输出优化器估算出的每个操作的记录行数、

字节数、代价和时间,以及相关的提示信息(如远程 SQL、优化器建议等)。如

果存在谓词(Predicate)条件,还会输出每个操作中的过滤(Filter)条件和访问

(Access)条件。此外,如果查询涉及分区表,还会输出分区裁剪信息 ;如果查询

涉及并行查询,还会输出并行操作的相关信息(如表队列信息、并行查询分布方

式等)。这种格式是默认格式。

❍ 'SERIAL' :串行执行格式。这种格式和典型格式的输出内容基本一致,不同之处在

于,对并行查询,它不会输出相关的并行内容。

❍ 'ALL' :完全格式。输出的内容相对完整。除了典型格式的内容以外,还会输出字

段投射信息和别名信息。

除了这些预定义的格式外,用户还可以通过在格式化字符串中添加或者屏蔽一些关

键词进行细化输出。每一个细化选项代表了输出内容中的单个信息(可能是执行计划表

中的一个列,也可能是一个附加信息)。在 DISPLAY 函数中,以下细化控制选项可供

选择:

❍ ROWS:优化器估算出的记录行数;

❍ BYTES:优化器估算出的字节数;

Page 6: 2 第一篇 执 - Baidu

6   第一篇 执 行 计 划

❍ COST:优化器估算出的代价;

❍ PARTITION:分区裁剪;

❍ PARALLEL:并行查询;

❍ PREDICATE:谓词;

❍ PROJECTION:字段投射;

❍ ALIAS:别名;

❍ REMOTE:分布式查询信息;

❍ NOTE:相关注释信息。

细化控制选项和预定格式一起使用。例如,如果你希望输出基本格式内容,并输出优化

器估算出的记录行数,可以用“BASIC ROWS”作为格式字符串;而如果希望输出典型格式,

但不要其中的谓词条件,则可以输入“TYPICAL -PREDICATE”作为格式字符串,即在希望

被屏蔽信息的对应控制选项前加上“-”。❑ FILTER_PREDS :该参数接收合法的谓词过滤条件(可以是谓词逻辑表达式,也可以

包含子查询),以过滤从查询计划表中读取的内容。例如,可以输入“COST > 10”以

限制输出所有估算代价大于 10 的操作。

示例见代码清单 1-2。

代码清单 1-2 显示执行计划(DISPLAY 函数)

HELLODBA.COM>explain plan for select * from t_users where user_id=:A;

Explained.

HELLODBA.COM>select * from table(dbms_xplan.display());

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------------------------

Plan hash value: 371495088

------------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

------------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 86 | 1 (0)| 00:00:02 |

| 1 | TABLE ACCESS BY INDEX ROWID| T_USERS | 1 | 86 | 1 (0)| 00:00:02 |

|* 2 | INDEX UNIQUE SCAN | T_USERS_PK | 1 | | 1 (0)| 00:00:02 |

------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - access("USER_ID"=TO_NUMBER(:A))

14 rows selected.

HELLODBA.COM>select * from table(dbms_xplan.display(null,null,'BASIC ROWS BYTES'));

PLAN_TABLE_OUTPUT

--------------------------------------------------------------------------------------------------

Plan hash value: 371495088

Page 7: 2 第一篇 执 - Baidu

第 1 章 生成和显示执行计划   7

------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes |

------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 86 |

| 1 | TABLE ACCESS BY INDEX ROWID| T_USERS | 1 | 86 |

| 2 | INDEX UNIQUE SCAN | T_USERS_PK | 1 | |

------------------------------------------------------------------

1.2.2.2 DISPLAY_CURSORDISPLAY_CURSOR 函数可以显示内存中一个或者多个游标的执行计划。同样,可以通

过输入参数限定 SQL、游标以及输出格式。

用户必须对视图 V$SQLV、$SQL_PLAN 和 V$SQL_PLAN_STATISTICS_ALL 的 SELECT有权限,才能正常调用 DISPLAY_CURSOR 函数。

参数描述:

❑ SQL_ID : 所 显 示 执 行 计 划 的 SQL 语 句 的 ID。 该 ID 可 以 从 V$SQL.SQL_ID、

V$SESSION.SQL_ID 或者 V$SESSION.PREV_SQL_ID 获得。如果没有指定 SQL_ID(指定 NULL),则默认会显示当前会话中最后一条执行的 SQL 语句。

❑ CURSOR_CHILD_NO :语句的子游标序号。我们知道,受到执行环境的影响,一条

SQL 语句可能会产生多个版本的子游标,每个子游标都会与一个执行计划相映射(多

个子游标也可能映射同一个执行计划)。通过 CURSOR_CHILD_NO 可以限制仅显示

某一个子游标的执行计划。如果不指定该参数,则会显示该语句的所有子游标的执行

计划。

❑ FORMAT :格式化控制字符串。DISPLAY 函数的格式化控制字符串的所有选项都

适用于 DISPLAY_CURSOR 函数。由于运行语句还可以通过提示 GATHER_PLAN_STATISTICS 或设置系统参数 STATISTICS_LEVEL 为“ALL”收集语句运行的性能

统计数据,因此在细化选项中还有额外的选项,以选择是否输出这些数据。

❍ IOSTATS:是否输出计划的输入输出(IO)统计数据;

❍ MEMSTATS :在启用了 PGA 自动管理(参数 pga_aggregate_target 的值大于 0)的情况下,是否输出计划的输入内存统计数据(操作的内存使用量、内存读次数

等);

❍ ALLSTATS:包含了 IOSTATS 和 MEMSTATS 的全部内容;

❍ LAST :以上三个选项输出的统计数据都是实际产生的数据,而非估算数据,它们

是该游标所有执行所产生的数据的总和。你可以增加 LAST 选项以限定仅显示最

后一次运行的统计数据。

此外,还有一些未公布的选项可用于该函数的输出控制。首先是预定义格式:

❍ 'ADVANCED' :高级格式。高级格式除了会输出完全格式中的所有内容外,还会视

情况输出绑定变量窥视信息和计划概要(Outline)信息;

❍ OUTLINE:是否以提示(HINT)的方式显示计划概要;

Page 8: 2 第一篇 执 - Baidu

8   第一篇 执 行 计 划

❍ PEEKED_BINDS:是否显示绑定变量窥视信息;

❍ BUFFSTATS :是否显示内存读次数(包括一致性读和当前读次数),该信息为

IOSTATS 的一部分;

❍ PLAN_HASH:是否显示计划的哈希值,该选项同样适用于 DISPLAY 函数。

示例见代码清单 1-3。

代码清单 1-3 显示执行计划(DISPLAY_CURSOR 函数)

HELLODBA.COM>var A number

HELLODBA.COM>exec :A:=5

PL/SQL procedure successfully completed.

HELLODBA.COM>select /*+gather_plan_statistics*/* from t_users where user_id=:A;

USERNAME USER_ID PASSWORD ACCOUNT_STATUS LOCK_DATE

EXPIRY_DATE DEFAULT_TABLESPACE TEMPORARY_TABLESPACE CREATED PROFILE

INITIAL_RSRC_CONSUMER_GROUP

------------------------------ ---------- ------------------------------ ----------------- -----------------

EXTERNAL_NAME

--------------------------------------------------------------------------------- ---------------

SYSTEM 5 2D594E86F93B17A1 OPEN

SYSTEM TEMP 2005-11-21 16:26:09 DEFAULT

SYS_GROUP

HELLODBA.COM>select * from table(dbms_xplan.display_cursor(null,null,'BASIC LAST ALLSTATS'));

PLAN_TABLE_OUTPUT

-----------------------------------------------------------------------------------------------

EXPLAINED SQL STATEMENT:

------------------------

select /*+gather_plan_statistics*/* from t_users where user_id=:A

Plan hash value: 371495088

---------------------------------------------------------------------------------

| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |

---------------------------------------------------------------------------------

| 1 | TABLE ACCESS BY INDEX ROWID| T_USERS | 1 | 1 | 1 |00:00:00.01 | 2 |

|* 2 | INDEX UNIQUE SCAN | T_USERS_PK | 1 | 1 | 1 |00:00:00.01 | 1 |

---------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - access("USER_ID"=:A)

18 rows selected.

1.2.2.3 DISPLAY_AWRDISPLAY_AWR 函数显示存储在 AWR 历史数据的执行计划。

提示 :要正常调用 DISPLAY_AWR 参数,必须对以下视图有权限 :DBA_HIST_SQL_PLAN 和 DBA_HIST_SQLTEXT 的 SELECT。

Page 9: 2 第一篇 执 - Baidu

第 1 章 生成和显示执行计划   9

参数描述:

❑ SQL_ID :所显示执行计划的 SQL 语句的 ID。该 ID 可以从 DBA_HIST_SQL_PLAN.SQL_ID 或 DBA_HIST_SQLTEXT.SQL_ID 获得,该参数必须指定非空值,没有默认

值;

❑ PLAN_HASH_VALUE :执行计划的哈希值。我们之前提到,每个执行计划都有一

个哈希值。通过该值,可以显示 SQL 语句的特定执行计划。如果该参数未指定或为

NULL,则会显示语句的所有执行计划;

❑ DB_ID:指定显示哪个数据库的执行计划,默认为本地数据库 ID;

提示:我们可以将其他数据库的 AWR 数据导入本地数据库进行分析。

❑ FORMAT:格式化控制字符串。与 DISPLAY 的相同选项类似。

示例见代码清单 1-4。

代码清单 1-4 显示执行计划(DISPLAY_AWR 函数)

HELLODBA.COM>select sql_id, to_char(substr(sql_text,0,4000)) from dba_hist_sqltext where

upper(sql_text) like 'SELECT * FROM T_USERS%';

SQL_ID

-------------

TO_CHAR(SUBSTR(SQL_TEXT,0,4000

-------------------------------------------------------------------------------------------------

d76shb2rbmmsn

select * from t_users where user_id=:A

HELLODBA.COM>select * from table(dbms_xplan.display_awr('d76shb2rbmmsn'));

PLAN_TABLE_OUTPUT

-------------------------------------------------------------------------------------------------

SQL_ID d76shb2rbmmsn

--------------------

select * from t_users where user_id=:A

Plan hash value: 371495088

---------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

---------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | | | 1 (100)| |

| 1 | TABLE ACCESS BY INDEX ROWID| T_USERS | 1 | 86 | 1 (0)| 00:00:02 |

| 2 | INDEX UNIQUE SCAN | T_USERS_PK | 1 | | 1 (0)| 00:00:02 |

---------------------------------------------------------------------------------

1.2.2.4 DISPLAY_SQLSETDISPLAY_SQLSET 函数显示存储在一个 SQL 调优集中的语句的执行计划。

提示:DBMS_SQLTUNE 是 Oracle 10g 中提供的一个自动调优的工具包,它可以对单条

语句进行调优,也可以对一组 SQL 集进行调优,我们在后面章节会做详细介绍。

Page 10: 2 第一篇 执 - Baidu

10   第一篇 执 行 计 划

参数描述:

❑ SQLSET_NAME :SQL 集的名称。每个 SQL 集都有一个单独的名称(可以是创建时

用户指定的,也可以是系统自动生成的),我们需要指定从哪个 SQL 集中读取和显示

语句的执行计划,该参数没有默认值,必须指定;

❑ SQL_ID : 所 显 示 执 行 计 划 的 SQL 语 句 的 ID。 该 ID 可 以 从 USER/DBA/ALL_SQLSET_PLANS.SQL_ID 获得,该参数必须指定非空值,没有默认值;

❑ PLAN_HASH_VALUE :执行计划的哈希值。如果未指定或为 NULL,则会显示语句

的所有执行计划;

❑ FORMAT:格式化控制字符串。与 DISPLAY 的 FORMAT 选项相同;

❑ SQLSET_OWNER:SQL 集的所有者,默认为当前用户名。

示例见代码清单 1-5。

代码清单 1-5 显示执行计划(DISPLAY_SQLSET 函数)

HELLODBA.COM>declare

2 ss_name varchar2(30);

3 begin

4 ss_name := dbms_sqltune.create_sqlset();

5 dbms_sqltune.capture_cursor_cache_sqlset(ss_name,300,100);

6 dbms_output.put_line(ss_name);

7 end;

8 /

STS_2

PL/SQL procedure successfully completed.

HELLODBA.COM>select sqlset_name,sql_id,sql_text from DBA_SQLSET_STATEMENTS where upper(sql_text)

like 'SELECT * FROM T_USERS%';

SQLSET_NAME SQL_ID SQL_TEXT

------------------------------ ------------- ------------------------------------

STS_2 d76shb2rbmmsn select * from t_users where user_id=:A

HELLODBA.COM>select * from table(dbms_xplan.display_sqlset('STS_2','d76shb2rbmmsn',null,'BASIC ROWS COST'));

PLAN_TABLE_OUTPUT

---------------------------------------------------------------------------------

SQL Tuning Set Name: STS_2

SQL Tuning Set Owner: DEMO

SQL_ID: d76shb2rbmmsn

SQL Text: select * from t_users where user_id=:A

-----------------------------------------------------------------------

Plan hash value: 371495088

-----------------------------------------------------------------------

| Id | Operation | Name | Rows | Cost (%CPU)|

-----------------------------------------------------------------------

| 1 | TABLE ACCESS BY INDEX ROWID| T_USERS | 1 | 1 (0)|

| 2 | INDEX UNIQUE SCAN | T_USERS_PK | 1 | 1 (0)|

-----------------------------------------------------------------------

Page 11: 2 第一篇 执 - Baidu

第 1 章 生成和显示执行计划   11

1.2.2.5 DISPLAY_SQL_PLAN_BASELINEDISPLAY_SQL_PLAN_BASELINE 函数显示存储在数据字典当中 SQL 执行计划基线的

计划。

提示 :SQL 执行计划管理是 Oracle 11g 中提供的一个新特性,用于管理 SQL 语句的一

组执行计划(执行计划基线,Plan Baseline),保证语句运行性能稳定性。

参数描述:

❑ SQL_HANDLE:执行计划基线所属 SQL 的句柄名称,它由 Oracle 在创建或载入执行计

划到基线当中时自动生成,可以通过视图 dba_sql_plan_baselines 查询,默认为 NULL;❑ PLAN_NAME :执行计划基线中某个执行计划的名称,它由 Oracle 在创建或载入执

行计划到基线当中时自动生成,可以通过视图 dba_sql_plan_baselines 查询,默认为

NULL;❑ FORMAT :格式化控制字符串。DISPLAY_SQLSET 函数的格式化选项与 DISPLAY

的选项相同。

当 SQL_HANDLE 和 PLAN_NAME 都为空时,显示所有基线数据中的全部执行计划。

示例见代码清单 1-6。

代码清单 1-6 显示执行计划(DISPLAY_SQL_PLAN_BASELINE 函数)

HELLODBA.COM>select * from table(dbms_xplan.display_sql_plan_baseline(sql_handle =>

'SYS_SQL_99cc41808e350a83'));

PLAN_TABLE_OUTPUT

---------------------------------------------------------------------------------

--------------------------------------------------------------------------------

SQL handle: SYS_SQL_99cc41808e350a83

SQL text: select count(last_ddl_time) from t_objects where object_id > :"SYS_B_0"

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

Plan name: SQL_PLAN_9mm21h273a2n319ac7bf0 Plan id: 430734320

Enabled: YES Fixed: NO Accepted: NO Origin: AUTO-CAPTURE

--------------------------------------------------------------------------------

Plan hash value: 1202886560

---------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

---------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 13 | 2 (0)| 00:00:01 |

| 1 | SORT AGGREGATE | | 1 | 13 | | |

| 2 | TABLE ACCESS BY INDEX ROWID| T_OBJECTS | 3606 | 46878 | 2 (0)| 00:00:01 |

|* 3 | INDEX RANGE SCAN | T_OBJECTS_PK | 649 | | 1 (0)| 00:00:01 |

---------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

3 - access("OBJECT_ID">TO_NUMBER(:SYS_B_0))

--------------------------------------------------------------------------------

Plan name: SQL_PLAN_9mm21h273a2n384ce3094 Plan id: 2228105364

Enabled: YES Fixed: NO Accepted: YES Origin: AUTO-CAPTURE

--------------------------------------------------------------------------------

Page 12: 2 第一篇 执 - Baidu

12   第一篇 执 行 计 划

Plan hash value: 230482234

--------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

--------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 1 | 13 | 296 (3)| 00:00:03 |

| 1 | SORT AGGREGATE | | 1 | 13 | | |

|* 2 | TABLE ACCESS FULL| T_OBJECTS | 3606 | 46878 | 296 (3)| 00:00:03 |

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - filter("OBJECT_ID">TO_NUMBER(:SYS_B_0))

1.2.3 AUTOTRACEAUTOTRACE 是 Oracle 自带的客户端工具 SQL*Plus 的一个特性。启用 AUTOTRACE

后,SQL*PLus 会自动收集执行过的语句的执行计划、性能统计数据等,并在语句执行结束

后显示在 SQL*Plus 中。

要使用 AUTOTRACE,需要先做以下准备,用 DBA 用户创建角色 PLUSTRCE,并将该

角色赋予用户:

HELLODBA.COM>conn sys/sys as sysdba

Connected.

HELLODBA.COM>@?/SQLPLUS/ADMIN/PLUSTRCE.SQL

HELLODBA.COM>grant plustrace to demo;

Grant succeeded.

在执行语句之前,在 SQL*Plus 中打开 AUTOTRACE。可以在打开 AUTOTRACE 时选

择不同选项,以控制输出的内容。选项如下所示:

❑ SET AUTOTRACE ON:打开 AUTOTRACE,并输出所有内容,包括语句本身的查询

结果、执行计划,以及性能统计数据。

❑ SET AUTOTRACE ON EXPLAIN :打开 AUTOTRACE,并输出语句本身的查询结果

和执行计划,不输出性能统计数据。

❑ SET AUTOTRACE ON STATISTICS :打开 AUTOTRACE,并输出语句本身的查询结

果和性能统计数据,不输出执行计划。

❑ SET AUTOTRACE TRACE :打开 AUTOTRACE,并输出执行计划和性能统计数据,

不输出语句本身的查询结果。

❑ SET AUTOTRACE TRACE EXPLAIN :打开 AUTOTRACE,并输出执行计划,不输

出语句本身的查询结果和性能统计数据。

❑ SET AUTOTRACE TRACE STATISTICS:打开 AUTOTRACE,并输出性能统计数据,

不输出语句本身的查询结果和执行计划。

❑ SET AUTOTRACE OFF:关闭 AUTOTRACE。一个完整的 AUTOTRACE 报告输出包括三个部分 :第一部分为 SQL 本身的执行结果 ;

Page 13: 2 第一篇 执 - Baidu

第 1 章 生成和显示执行计划   13

第二部分为 SQL 的执行计划 ;第三部分为 SQL 实际执行的性能统计数据。由于执行计划和

执行的性能数据都是进行 SQL 调优时的重要参考信息,因此 AUTOTRACE 是进行 SQL 语句

性能调优的一个非常实用的辅助方法。

提示:当打开 AUTOTRACE 后,在执行语句之前,Oracle 会调用 EXPLAIN PLAN 命令

对语句进行解析 ;在执行完成后,从 PLAN_TABLE 中查询和显示执行计划。因此,由于受

到共享游标、绑定变量窥视等设置的影响,这一执行计划可能会与实际执行计划不同。

1.2.4 其他方法

除了上述方法外,我们还可以通过其他一些途径获取到语句的执行计划。但在这些方法

所产生的数据里,执行计划通常仅是辅助我们解决问题的一个部分,而非重点。

1.2.4.1 SQL_TRACE(或者 10046 跟踪事件)

SQL_TRACE 跟踪的内容由三个部分组成:执行语句时造成的等待事件(Waits)、执行语句

时产生的性能统计数据,以及语句的执行计划和绑定变量信息。这里仅介绍执行计划相关部分。

在会话或者系统中启动 SQL 跟踪后,会话结束或者关闭 SQL 跟踪之前,会话(或系

统)中所有运行的语句的性能统计数据都会记录到 UDUMP 目录(user_dump_dest 参数指

定)下一个跟踪文件中(未指定标识字符串 tracefile_identifier 的情况下,文件名格式为

<ORACLE_SID>_ORA_<PID>.trc),从跟踪文件中,我们可以找到语句的执行计划。示例见

代码清单 1-7。

代码清单 1-7 SQL_TRACE

HELLODBA.COM>alter session set sql_trace=true;

Session altered.

HELLODBA.COM>select * from t_users where user_id=:A;

USERNAME USER_ID PASSWORD ACCOUNT_STATUS LOCK_DATE

EXPIRY_DATE DEFAULT_TABLESPACE TEMPORARY_TABLESPACE CREATED PROFILE

INITIAL_RSRC_CONSUMER_GROUP

------------------------------ ---------- ------------------------------ ------------------------

EXTERNAL_NAME

-------------------------------------------------------------------------------------------------

SYSTEM 5 2D594E86F93B17A1 OPEN

SYSTEM TEMP 2005-11-21 16:26:09 DEFAULT SYS_GROUP

HELLODBA.COM>alter session set sql_trace=false;

Session altered.

HELLODBA.COM>select distinct spid from v$process p, v$session s, v$mystat m where p.addr=s.paddr

and s.sid=m.sid;

SPID

------------

7364

HELLODBA.COM>show parameter user_dump_destNAME TYPE VALUE------------------------------------ -------------------------------- user_dump_dest string D:\ORACLE\PRODUCT\10.2.0\ADMIN\EDGAR\UDUMPHELLODBA.COM>ed D:\ORACLE\PRODUCT\10.2.0\ADMIN\EDGAR\UDUMP\edgar_ora_7364.trc...

Page 14: 2 第一篇 执 - Baidu

14   第一篇 执 行 计 划

STAT #52 id=1 cnt=1 pid=0 pos=1 obj=246864 op='TABLE ACCESS BY INDEX ROWID T_USERS (cr=2 pr=0 pw=0 time=23 us)'STAT #52 id=2 cnt=1 pid=1 pos=1 obj=246865 op='INDEX UNIQUE SCAN T_USERS_PK (cr=1 pr=0 pw=0 time=12 us)'...

1.2.4.2 OPTIMIZER_TRACE(或者 10053 跟踪事件)

OPTIMIZER_TRACE 可以跟踪优化器生成语句执行计划的整个过程,并且,在 11g中还可以通过设置事件来指定仅跟踪一个或多个组件的信息。同样,其跟踪内容都会写入

UDMP 目录下的一个跟踪文件中,文件的命名方式和 SQL_TRACE 产生的跟踪文件的命名方

式相同。示例见代码清单 1-8。

代码清单 1-8 OPTIMIZER_TRACE

HELLODBA.COM>alter session set "_optimizer_trace"=ALL;Session altered.

HELLODBA.COM>explain plan for select * from t_users where username=:B;Explained.

HELLODBA.COM>alter session set "_optimizer_trace"=NONE;Session altered.

HELLODBA.COM>select distinct spid from v$process p, v$session s, v$mystat m where p.addr=s.paddr and s.sid=m.sid;SPID------------5832

HELLODBA.COM>ed D:\ORACLE\PRODUCT\10.2.0\ADMIN\EDGAR\UDUMP\edgar_ora_5832.trc...sql_id=0prs2asa1zgq6.Current SQL statement for this session:explain plan for select * from t_users where username=:B ============Plan Table============-------------------------------------+-----------------------------------+| Id | Operation | Name | Rows | Bytes | Cost | Time |-------------------------------------+-----------------------------------+| 0 | SELECT STATEMENT | | | | 2 | || 1 | TABLE ACCESS FULL | T_USERS | 1 | 86 | 2 | 00:00:03 |-------------------------------------+-----------------------------------+Predicate Information:----------------------1 - filter("USERNAME"=:B)

...