Oracle中如何生成有用的SQL 执行计划(译)

简介: 漫画戴夫·艾伦(Dave Allen)曾经讲过一个古老的笑话,一个旅行者问路人去某个城镇的路,路人只是说:“如果我是你,我就不会从这里开始。”

漫画戴夫·艾伦(Dave Allen)曾经讲过一个古老的笑话,一个旅行者问路人去某个城镇的路,路人只是说:“如果我是你,我就不会从这里开始。”当涉及到SQL执行计划时,如果你从错误的地方开始,那么你可能不会到达目的地。这篇文章的目的是盘点一下我认为收集SQL执行计划的最佳方法,这些方法可以确保你捕获真正有用的信息, 澄清一下我指的“有用的信息”是什么意思:我的意思是捕获一个SQL执行计划,它可以帮助你了解SQL是如何执行的,并弄清楚SQL语句执行慢的根源。SQL 执行计划揭示了 Oracle 数据库计划如何执行SQL 语句的大量信息。您并不需要熟悉 SQL 执行计划才能成为 Oracle 数据库专家,但我们大多数人都喜欢学习新事物,有时看看机器内部的东西很有趣。这篇文章中有很多观点,所以非常欢迎评论。

这又是一篇关于 SQL 执行计划的文章?

我知道书中有很多关于生成SQL执行计划的文章和章节,但我这篇文章的目的是要把众多方法提炼成在大多数情况下都管用的少数几种方法,大多数的执行计划钟经常存在3类问题:

  1. 缺少的重要信息
  2. 存在一些盲点——经常被提及但又经常被忽略的有效方法
  3. 缺少如果你不要求它,你就不会看到的有用的信息

您可能会认为自己是唯一一个认为SQL执行计划难以理解的人,但实际上,它们的确很难理解——它们的庞大规模可能令人生畏。如果缺少某些细节,则几乎无法对执行计划进行评估。某些SQL的转换和操作给出的数字(例如行数)与预期不一致,这会让你很困惑。下面的示例生成了许多有用的信息,但刚开始您可能会觉得有些信息没有必要。这些信息被分解为若干个子集(或通过企业管理器的图像界面展示),因此便于分开解读或干脆先忽略。我没有在下面列出所有示例的输出,因为它会占用太多空间,所以我将一些自包含脚本上传到 GitHub(https://github.com/oracle/oracle-db-examples/tree/master/optimizer/execution_plans/part0)。

例子

下面的例子是我对不同的情况给出的不同的建议。

示例 A

如果可以在SQL Plus 或者 SQLcl 里执行SQL:



select e.ename,r.rnamefrom   employees  ejoin   roles       r on (r.id = e.role_id)join   departments d on (d.id = e.dept_id)where  e.staffno <= 10and    d.dname in ('Department Name 1','Department Name 2');
SELECT *FROM table(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'ALL +OUTLINE'));

或者,如果您不想执行SQL:



explain plan forselect  e.ename,r.rnamefrom    employees  ejoin    roles       r on (r.id = e.role_id)join    departments d on (d.id = e.dept_id)where   e.staffno <= 10and     d.dname in ('Department Name 1','Department Name 2');
SELECT *FROM table(DBMS_XPLAN.DISPLAY (FORMAT=>'ALL +OUTLINE'));

这个例子的一个重要特点是我使用的是 FORMAT=>'ALL +OUTLINE',它记录了“ALL”格式,并简要提到了“OUTLINE”。

示例 B

如果无法单独运行SQL,仍可以使用如下所示的SQL从游标缓存中获取计划信息:



SELECT *FROM table(DBMS_XPLAN.DISPLAY_CURSOR(            SQL_ID=>'the_SQL_ID',             CHILD_NUMBER=>the_child_number,             FORMAT=>'ALL +OUTLINE'));

这里需要SQL的SQL_ID和CHILD_NUMBER做为输入参数,有很多方法可以得到这两个参数,如果您有DBA权限,那么您可以在V$SQL中找到这两个参数:





select /* MY_TEST_QUERY */       e.ename,r.rnamefrom   employees  ejoin   roles       r on (r.id = e.role_id)join   departments d on (d.id = e.dept_id)where  e.staffno <= 10and    d.dname in ('Department Name 1','Department Name 2');
select sql_id, child_number, sql_textfrom   v$sql where  sql_text like '%MY_TEST_QUERY%'and    sql_text not like '%v$sql%';

上面的计划不包含任何运行时信息,因此您不会看到计划的每个部分执行所花费的时间或实际处理的行数。例如,“Rows”是估计值,它不会告诉您实际处理了多少行。如果您能收集到运行时信息,对了解SQL的实际执行效率会有很大的帮助,那么如何去得到它呢?

示例 C

您可以使用hint来收集运行时信息:





select /*+ gather_plan_statistics */       e.ename,r.rnamefrom   employees  ejoin   roles       r on (r.id = e.role_id)join   departments d on (d.id = e.dept_id)where  e.staffno <= 10and    d.dname in ('Department Name 1','Department Name 2');
SELECT *FROM table(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'ALLSTATS LAST ALL +OUTLINE'));


这将向您显示统计信息,例如实际处理的行数(A-Rows),而不仅仅是估计值(E-Rows),它还包括一个名为“Starts”的列,该列告诉您每个步骤执行了多少次。如果您想了解计划,A-Rows, E-RowsStarts都非常有用。

示例 D

如果不想更改SQL文本以添加hint,可以设置一个参数:




alter session set statistics_level='ALL';
select e.ename,r.rnamefrom   employees  ejoin   roles       r on (r.id = e.role_id)join   departments d on (d.id = e.dept_id)where  e.staffno <= 10and    d.dname in ('Department Name 1','Department Name 2');
SELECT *FROM table(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'ALLSTATS LAST ALL +OUTLINE'));


示例 E

DBMS_XPLAN 'ALLSTATS LAST' 不会在执行SQL时为您提供运行时统计信息的连续视图,但 SQL Monitor 解决了这个问题。它需要Oracle Tuning包,因此请参考数据库版本的许可证用户指南(https://docs.oracle.com/en/database/oracle/oracle-database/12.2/dblic/Licensing-Information.html)。此工具非常适合生成计划和监视 SQL,它可通过企业管理器的性能中心的图像界面调用,也可以在命令行上调用:




select /*+ MONITOR */       e.ename,r.rnamefrom   employees  ejoin   roles       r on (r.id = e.role_id)join   departments d on (d.id = e.dept_id)where  e.staffno <= 10and    d.dname in ('Department Name 1','Department Name 2');
-- Get the SQL ID of the query we just executedselect prev_sql_idfrom   v$sessionwhere  sid=userenv('sid')and    username is not nulland    prev_hash_value <> 0;
PREV_SQL_ID-------------an05rsj1up1k5
set linesize 250 pagesize 0 trims on tab off long 1000000column report format a220
select   DBMS_SQL_MONITOR.REPORT_SQL_MONITOR        (sql_id=>'an05rsj1up1k5',report_level=>'ALL') reportfrom dual;

输出:

SQL_ID 参数是可选的,但我通常显式设置它,因为系统中可能有多个长时间运行的SQL,因此默认报告有时会选取不同的 SQL 语句。数据库会自动调用SQL Monitor 监控长时间运行的SQL,但这里我使用了 MONITOR 提示,因为这个SQL执行的时间很短。在SQL执行时监视SQL可能很有用,因为您可以观察其进度,您可以在另一个会话中监视SQL,并查看其统计信息不断更新。您不必等待它完成才能弄清楚SQL的哪个部分花费了很长时间。请注意,您可以像上面的示例 B一样使用“ALL +OUTLINE ”获得更加详细的信息。您甚至可以使用命令行生成活动的 HTML 报告。只需像这样运行报告:


-- spool output to a file, then…select DBMS_SQL_MONITOR.REPORT_SQL_MONITOR        (sql_id       =>'an05rsj1up1k5',         report_level =>'all',          type         =>'ACTIVE') reportfrom dual;


然后在浏览器中打开生成的报告,则会得到如下所示的交互式 HTML 页面:


请注意,浏览器需要访问互联网,因为 HTML 报告会下载一些外部资源。

示例 F

我知道你们中的许多人都喜欢命令行(我也一样),但您也应该在Oracle Enterprise Manager Performance Hub中尝试一下SQL Monitor。在这里访问SQL Monitor的报告要容易得多,并且它们将随着SQL执行而不断刷新。此外,保存这些报告并将其发送给其他人也很容易。只需使用“保存”按钮(下面用红色圈出)。

如果您点击“Plan”选项卡,如果计划不是太大,看图形视图会更易读。我喜欢选择“Rotate”来给我一棵垂直方向的树。啊哈!现在我可以看到连接的左侧和右侧的实际意义了!总的来说,您应该从左下角开始阅读这个执行树。我以后可能会另外写篇文章阐述这个问题。在下面的示例中,与上面的示例一样,数据库首先读取 DEPARTMENTS表,再把读取的记录与 EMPLOYEE表进行连接,再将输出的结果和 ROLES表进行连接。


示例 G

最后,还有SQL Developer工具!

使用DBMS_XPLAN:


总结

如果您想保存和分析一个执行计划,您可以对比以下一些选项:

相关文章
|
2月前
|
SQL 监控 Oracle
Oracle SQL性能优化全面指南
在数据库管理领域,Oracle SQL性能优化是确保数据库高效运行和数据查询速度的关键
|
2月前
|
SQL 存储 Oracle
Oracle数据库SQL语句详解与应用指南
在数字化时代,数据库已成为各类企业和组织不可或缺的核心组件。Oracle数据库作为业界领先的数据库管理系统之一,广泛应用于各种业务场景。掌握Oracle数据库的SQL语句是数据库管理员、开发人员及运维人员的基本技能。本文将详细介绍Oracle数据库SQL语句的基本概念、语法、应用及最佳实践。一、Or
81 3
|
2月前
|
SQL Oracle 关系型数据库
Oracle SQL:了解执行计划和性能调优
Oracle SQL:了解执行计划和性能调优
70 1
|
5月前
|
SQL 分布式计算 MaxCompute
SQL开发问题之对于ODPS中的UNION操作,执行计划的问题如何解决
SQL开发问题之对于ODPS中的UNION操作,执行计划的问题如何解决
|
5月前
|
SQL 分布式计算 MaxCompute
ODPS SQL问题之为什么使用odps.sql.groupby.skewindata = true优化后,逻辑执行计划会发生改变如何解决
ODPS SQL问题之为什么使用odps.sql.groupby.skewindata = true优化后,逻辑执行计划会发生改变如何解决
119 0
|
5月前
|
SQL 存储 Oracle
TDengine 3.3.2.0 发布:新增 UDT 及 Oracle、SQL Server 数据接入
**TDengine 3.3.2.0 发布摘要** - 开源与企业版均强化性能,提升WebSocket、stmt模式写入与查询效率,解决死锁,增强列显示。 - taos-explorer支持geometry和varbinary类型。 - 企业版引入UDT,允许自定义数据转换。 - 新增Oracle和SQL Server数据接入。 - 数据同步优化,支持压缩,提升元数据同步速度,错误信息细化,支持表名修改。 - 扩展跨平台支持,包括麒麟、Euler、Anolis OS等。
131 0
|
Oracle 关系型数据库 数据库
|
SQL Oracle 关系型数据库
Oracle 历史SQL语句执行计划的对比与分析
    基于CBO优化器的环境中,SQL执行计划的生成依赖于统计信息的真实与完整。如列的离散度,列上的直方图,索引的可用性,索引上的聚簇因子。当这些信息是真实完整的情况下,CBO优化器通常都可以制定最优的执行计划。
1382 0
|
2月前
|
存储 Oracle 关系型数据库
Oracle数据库的应用场景有哪些?
【10月更文挑战第15天】Oracle数据库的应用场景有哪些?
192 64
|
12天前
|
存储 Oracle 关系型数据库
数据库数据恢复—ORACLE常见故障的数据恢复方案
Oracle数据库常见故障表现: 1、ORACLE数据库无法启动或无法正常工作。 2、ORACLE ASM存储破坏。 3、ORACLE数据文件丢失。 4、ORACLE数据文件部分损坏。 5、ORACLE DUMP文件损坏。
51 11

推荐镜像

更多