返回顶部
首页 > 资讯 > 数据库 >在Oracle中,如何得到真实的执行计划?
  • 209
分享到

在Oracle中,如何得到真实的执行计划?

2024-04-02 19:04:59 209人浏览 八月长安
摘要

<h2 color:#000000;font-size:16px;margin:0px;padding:0px;white-space:nORMal;background-color:#ffffff;

<h2 color:#000000;font-size:16px;margin:0px;padding:0px;white-space:nORMal;background-color:#ffffff;"="" style="Word-wrap: break-word; margin: 0px; padding: 0px;">Oracle查看执行计划的几种方法:http://blog.itpub.net/26736162/viewspace-2136865/ 





一、  如何得到真实的执行计划?

oracle数据库中判断得到的执行计划是否准确,就是看目标sql是否被真正执行过,真正执行过的SQL所对应的执行计划就是准确的,反之则有可能不准,因此,通过10046事件及如下的几种方式得到的执行计划是最准确的,而从其它方式获取到的执行计划都有可能不准确。

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ADVANCED ALLSTATS'));

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('sql_id/hash_value',CHILD_CURSOR_NUMBER, 'ADVANCED ALLSTATS'));

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('sql_id'));


这里需要注意的是,虽然SQL*Plus的AUTOTRACE功能有部分是真实执行了SQL语句的(例如所有DML语句),但是,由于该命令所显示的执行计划来源于调用EXPLaiN PLAN命令,所以,其得到的执行计划依然可能不准确(特别是在使用了绑定变量的情况下)。那么,为什么EXPLAIN PLAN命令里显示的预估执行计划与该SQL真实的执行计划不一样呢?原因有多个方面,常见的情况包括以下几个方面:

① 绑定变量窥视(Bind Peeking):EXPLAIN PLAN里不会进行绑定变量窥视,但是Runtime Plan里会进行绑定变量窥视,所以,如果发生这种情况,那么会使这两个执行计划产生差异。

② 隐式转换:Explain Plan里不会考虑绑定变量的类型,但是Runtime Plan里会考虑类型,从而有可能会根据绑定变量的类型出现隐式转换,所以谓词(Predicate)会发生变化,使得执行计划也会产生差异。

③ 优化器参数:执行Explain Plan的Session与Runtime Plan的Session不是同一个。如果各个Session之间存在优化器参数差异,那么执行计划也会产生差异。

④ 统计信息收集参数:Explain Plan始终是用最新的统计信息产生执行计划,但是,Runtime Plan不一定会用最新的统计信息。因此也会产生执行计划差异。在收集统计信息时,一个与缓存的游标是否失效的很重要的参数为NO_INVALIDATE。在重新收集统计信息时,可以指定NO_INVALIDATE选项。该选项有TRUE、FALSE和DBMS_STATS.AUTO_INVALIDATE这3个值。如果取值为TRUE,那么表示收集统计信息后不进行游标失效动作,原有的Shared Cursor保持原有状态。如果取值为FALSE,那么表示将统计信息对象相关的所有Cursor全部失效,目标SQL语句在下次执行时就会使用硬解析。如果设置为AUTO_INVALIDATE,那么Oracle自己决定Shared Cursor失效动作,当SQL再次执行时间距离上次收集统计信息的时间超过5小时(隐含参数“_OPTIMIZER_INVALIDATION_PERIOD”决定)则对SQL重新做硬解析。AUTO_INVALIDATE为默认选项。有些DBA在收集统计信息时,没有使用NO_INVALIDATE=>FALSE选项,所以,即使收集了统计信息,执行计划也不会立即改变。可以在表级别设置让所有依赖于该表的游标不失效,设置方法为:

EXEC DBMS_STATS.SET_TABLE_PREFS('SH','SALES','NO_INVALIDATE','TRUE');--在收集SH.SALES表上的统计信息时,让所有依赖于该表的游标不失效






实验一:

CREATE TABLE TEST_EXPLAIN_LHR AS SELECT * FROM DBA_OBJECTS;

INSERT INTO TEST_EXPLAIN_LHR SELECT * FROM TEST_EXPLAIN_LHR;

COMMIT;

SELECT COUNT(*) FROM TEST_EXPLAIN_LHR;

 

CREATE INDEX IDX_OBJ_LHR ON  TEST_EXPLAIN_LHR(OBJECT_ID);

EXEC DBMS_STATS.GATHER_TABLE_STATS(USER,'test_explain_lhr',ESTIMATE_PERCENT => 100,CASCADE => TRUE);

 

VAR X NUMBER;

VAR Y NUMBER;

EXEC :X := 0;

EXEC :Y := 100000;

 

EXPLAIN PLAN FOR SELECT COUNT(*) FROM TEST_EXPLAIN_LHR T WHERE T.OBJECT_ID BETWEEN :X AND :Y ;

 

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

 

 

SET AUTOT ON

SELECT COUNT(*) FROM TEST_EXPLAIN_LHR T WHERE T.OBJECT_ID BETWEEN :X AND :Y ;

 

SET AUTOT OFF

SELECT COUNT(*) FROM TEST_EXPLAIN_LHR T WHERE T.OBJECT_ID BETWEEN :X AND :Y ;

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'advanced'));

下面实验验证了使用EXPLAIN PLAN FOR和SET AUTOT ON方式获取到的执行计划都是不准确的:

SYS@PROD1> clear scr

SYS@PROD1> CREATE TABLE test_explain_lhr AS SELECT * FROM Dba_Objects;

 

Table created.

 

SYS@PROD1> INSERT INTO test_explain_lhr SELECT * FROM test_explain_lhr;

 

72503 rows created.

 

SYS@PROD1> COMMIT;

 

Commit complete.

 

SYS@PROD1> SELECT COUNT(*) FROM test_explain_lhr;

 

  COUNT(*)

----------

    145006

 

SYS@PROD1> CREATE INDEX idx_obj_lhr ON  test_explain_lhr(object_id);

 

Index created.

 

SYS@PROD1> EXEC dbms_stats.gather_table_stats(USER,'test_explain_lhr',estimate_percent => 100,cascade => TRUE);

 

PL/SQL procedure successfully completed.

 

SYS@PROD1> VAR x NUMBER;

SYS@PROD1> VAR y NUMBER;

SYS@PROD1> EXEC :x := 0;

 

PL/SQL procedure successfully completed.

 

SYS@PROD1> EXEC :y := 100000;

 

PL/SQL procedure successfully completed.

 

SYS@PROD1> EXPLAIN PLAN FOR SELECT COUNT(*) FROM test_explain_lhr t WHERE t.object_id BETWEEN :x AND :y ;

 

Explained.

 

 

SYS@PROD1> set line 9999

SYS@PROD1> SELECT * FROM TABLE(dbms_xplan.display);

 

PLAN_TABLE_OUTPUT

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

Plan hash value: 3299589416

 

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

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

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

|   0 | SELECT STATEMENT   |             |     1 |     5 |     3   (0)| 00:00:01 |

|   1 |  SORT AGGREGATE    |             |     1 |     5 |            |          |

|*  2 |   FILTER           |             |       |       |            |          |

|*  3 |    INDEX RANGE SCAN| IDX_OBJ_LHR |   363 |  1815 |     3   (0)| 00:00:01 |

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

 

Predicate Information (identified by operation id):

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

 

   2 - filter(TO_NUMBER(:X)<=TO_NUMBER(:Y))

   3 - access("T"."OBJECT_ID">=TO_NUMBER(:X) AND

              "T"."OBJECT_ID"<=TO_NUMBER(:Y))

 

17 rows selected.

 

SYS@PROD1> set autot on

SYS@PROD1> SELECT COUNT(*) FROM test_explain_lhr t WHERE t.object_id BETWEEN :x AND :y ;

 

  COUNT(*)

----------

    145006

 

 

Execution Plan

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

Plan hash value: 3299589416

 

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

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

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

|   0 | SELECT STATEMENT   |             |     1 |     5 |     3   (0)| 00:00:01 |

|   1 |  SORT AGGREGATE    |             |     1 |     5 |            |          |

|*  2 |   FILTER           |             |       |       |            |          |

|*  3 |    INDEX RANGE SCAN| IDX_OBJ_LHR |   363 |  1815 |     3   (0)| 00:00:01 |

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

 

Predicate Information (identified by operation id):

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

 

   2 - filter(TO_NUMBER(:X)<=TO_NUMBER(:Y))

   3 - access("T"."OBJECT_ID">=TO_NUMBER(:X) AND

              "T"."OBJECT_ID"<=TO_NUMBER(:Y))

 

 

Statistics

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

          1  recursive calls

          0  db block gets

        329  consistent gets

          0  physical reads

          0  redo size

        424  bytes sent via SQL*Net to client

        419  bytes received via SQL*Net from client

          2  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

          1  rows processed

 

SYS@PROD1> SET AUTOT OFF

SYS@PROD1> SELECT COUNT(*) FROM test_explain_lhr t WHERE t.object_id BETWEEN :x AND :y ;

 

  COUNT(*)

----------

    145006

 

SYS@PROD1> SELECT * FROM TABLE(dbms_xplan.display_cursor(NULL,NULL,'advanced'));

 

PLAN_TABLE_OUTPUT

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

SQL_ID  1r87sg98rdkuf, child number 0

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

SELECT COUNT(*) FROM test_explain_lhr t WHERE t.object_id BETWEEN :x

AND :y

 

Plan hash value: 2428225634

 

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

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

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

|   0 | SELECT STATEMENT       |             |       |       |    90 (100)|          |

|   1 |  SORT AGGREGATE        |             |     1 |     5 |            |          |

|*  2 |   FILTER               |             |       |       |            |          |

|*  3 |    INDEX FAST FULL SCAN| IDX_OBJ_LHR |   145K|   708K|    90   (2)| 00:00:02 |

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

 

Query Block Name / Object Alias (identified by operation id):

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

 

   1 - SEL$1

   3 - SEL$1 / T@SEL$1

 

Outline Data

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

 

 

 

Peeked Binds (identified by position):

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

 

   1 - :X (NUMBER): 0

   2 - :Y (NUMBER): 100000

 

Predicate Information (identified by operation id):

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

 

   2 - filter(:X<=:Y)

   3 - filter(("T"."OBJECT_ID">=:X AND "T"."OBJECT_ID"<=:Y))

 

Column Projection Information (identified by operation id):

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

 

   1 - (#keys=0) COUNT(*)[22]

 

 

53 rows selected.

 

二、  如何在不执行SQL的情况下获取执行计划?

1、“EXPLAIN PLAN FOR SQL”不实际执行SQL语句,生成的计划未必是真实执行的计划。但是,必须要有PLAN_TABLE表,可以执行脚本“@?/rdbms/admin/utlxplan.sql”来创建。

2、SQL*Plus的AUTOTRACE功能,命令:SET AUTOTRACE TRACEONLY EXPLAIN。除SET AUTOTRACE TRACEONLY EXPLAIN外其它的AUTOTRACE方式均实际执行SQL。但是,如果该命令后执行的是DML语句,那么该DML语句是确实被Oracle实际执行过的。

三、  如何获取SQL历史执行计划?

历史执行计划只能从AWR中获取,如果AWR没有记录的话,那么就无法获取历史执行计划了,获取历史执行计划的命令如下所示:

SELECT  * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('&sqlid'));

对于历史计划,可以生成SQL报告,命令如下所示:

SELECT * FROM TABLE(DBMS_WORKLOAD_REPOSITORY.AWR_SQL_REPORT_html(L_DBID => , L_INST_NUM => , L_BID => , L_EID => , L_SQLID => )) ;

其中,L_DBID代表数据库的DBID,L_INST_NUM代表数据库的实例号,单机环境为1,RAC环境填写具体的实例号,L_BID为开始的快照号,L_EID为结束的快照号,L_SQLID为要查看SQL的SQL_ID。

下面的例子可以直接从AWR中获取SQL_ID为“bsa0wjtftg3uw”的执行计划,可以看到历史有2种执行计划,一个是全表扫描,一个是索引范围扫描:

SYS@RAC2LHR1> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR(SQL_ID => 'bsa0wjtftg3uw' )) ;

SQL_ID bsa0wjtftg3uw

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

SELECT file# FROM file$ WHERE ts#=:1

Plan hash value: 690176192

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

| Id  | Operation                   | Name    |

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

|   0 | SELECT STATEMENT            |         |

|   1 |  TABLE ACCESS BY INDEX ROWID| FILE$   |

|   2 |   INDEX RANGE SCAN          | I_FILE2 |

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

Note

-----

   - rule based optimizer used (consider using cbo)

SQL_ID bsa0wjtftg3uw

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

SELECT file# FROM file$ WHERE ts#=:1

Plan hash value: 3494626068

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

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

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

|   0 | SELECT STATEMENT  |       |       |       |     2 (100)|          |

|   1 |  TABLE ACCESS FULL| FILE$ |     1 |     6 |     2   (0)| 00:00:01 |

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

31 rows selected.

四、  给出一个执行计划的执行顺序

阅读如下的执行计划,给出SQL的执行顺序。

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

| Id  | Operation

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

|   0 | SELECT STATEMENT

|   1 |  SORT AGGREGATE

|   2 |   VIEW

|   3 |    UNION-ALL

|*  4 |     FILTER

|*  5 |      HASH JOIN

|   6 |       TABLE ACCESS FULL

|*  7 |       TABLE ACCESS FULL

|*  8 |      TABLE ACCESS BY INDEX ROWID

|*  9 |       INDEX UNIQUE SCAN

|  10 |     NESTED LOOPS

|  11 |      INDEX FULL SCAN

|  12 |      TABLE ACCESS CLUSTER

|* 13 |       INDEX UNIQUE SCAN

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

分析:采用最右最上最先执行的原则看层次关系,在同一级如果某个动作没有子ID,那么就最先执行,首先,6、7、9、13最右,所以,6,7最先执行做HASH JOIN,为6,7,5。

第二,8有子节点,接下来是9,8。

第三,HASH的结果和8的结果做FILTER过滤。

第四,10这个节点根据原则是11,13,12,10。

第五,剩下依次是3,2,1,0。

所以,该图的执行顺序是6,7,5,9,8,4,11,13,12,10,3,2,1,0。



您可能感兴趣的文档:

--结束END--

本文标题: 在Oracle中,如何得到真实的执行计划?

本文链接: https://lsjlt.com/news/50298.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 在Oracle中,如何得到真实的执行计划?
    <h2 color:#000000;font-size:16px;margin:0px;padding:0px;white-space:normal;background-color:#ffffff;...
    99+
    2024-04-02
  • Oracle中如何得到真实的执行计划
    之前介绍过4种在Oracle数据库里查看执行计划的方法:explain plan 命令DBMS_XPLAN包SQLPLUS中的AUTOTRACE开关10046事件其中除了第四种方法之外,其他三种方法得到的执...
    99+
    2024-04-02
  • 如何得到真实的执行计划
        通常,我们可以使用如下四种方法来得到目标sql的执行计划:(1)explain plan命令(2)dbms_xplan包(3)sqlplus中的autotra...
    99+
    2024-04-02
  • 查看oracle 真实执行计划
    一共3个step;step1:在sql执行时,增加hint:   step2:查出sql的sql id:  select * from v$sql s wher...
    99+
    2024-04-02
  • Oracle中如何查看执行计划
    这篇文章主要介绍了Oracle中如何查看执行计划,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。方法一、通过使用工具PLSQL Develop...
    99+
    2024-04-02
  • Oracle如何查看执行计划
    一、如何查看执行计划在Oracle数据库里,我们通常可以使用如下方法(包括但不限于)得到目标SQL的执行计划:explain plan 命令DBMS_XPLAN包SQLPLUS中的AUTOTRACE开关10...
    99+
    2024-04-02
  • Oracle如何解读执行计划
    这篇文章给大家分享的是有关Oracle如何解读执行计划的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。我先上一条语句,因为我觉得这条比较典型,所以我们就先用这条的执行计划来解读下执...
    99+
    2024-04-02
  • 看懂Oracle中的执行计划
       从事Oracle相关的工作,从最初的一脸懵逼到现在的略有所知,也来总结一下自己最近学习关于Oracle中SQL语句的执行计划的相关内容。下面是文章的目录结构: ...
    99+
    2024-04-02
  • oracle中如何查看SQL的执行计划方法
    这篇文章主要介绍了oracle中如何查看SQL的执行计划方法,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Oracle查看SQL执行计划的方...
    99+
    2024-04-02
  • 如何在ODBC连接Oracle时优化SQL执行计划
    要在ODBC连接Oracle时优化SQL执行计划,可以考虑以下几点: 使用索引:确保在查询中使用了适当的索引,可以加快查询的执行速度。 统计信息:确保表和索引的统计信息是最新的,可以通过收集统计信息来帮助优化执行计划。 使用HI...
    99+
    2024-07-16
    oracle
  • Mysql中如何查看执行计划
    目录explain执行计划包含的信息各字段详解idselect_typetypepossible_keyskeykey_lenrefrowsExtra综合Case执行顺序使用explain关键字可以模拟优化器执...
    99+
    2024-04-02
  • SQLSERVER中如何获取执行计划
    SQLSERVER中如何获取执行计划,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。得到执行计划的方式有两种: 1、一种是在指令的...
    99+
    2024-04-02
  • PostgreSQL中如何查看执行计划
    在 PostgreSQL 中,可以使用 EXPLAIN 命令来查看查询语句的执行计划。执行计划显示了 PostgreSQL 优化器将...
    99+
    2024-04-09
    PostgreSQL
  • oracle中怎么查看sql执行计划的执行顺序
    这篇文章主要讲解了“oracle中怎么查看sql执行计划的执行顺序”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“oracle中怎么查看sql执行计划的执行顺...
    99+
    2024-04-02
  • Oracle中如何分析执行计划和性能统计信息
    在Oracle数据库中,可以通过以下几种方式来分析执行计划和性能统计信息: 使用SQL语句explain plan来分析执行计划...
    99+
    2024-04-09
    Oracle
  • plsql的执行计划如何查看
    在PL/SQL中,可以使用以下方法来查看执行计划: 使用DBMS_XPLAN包:这是Oracle提供的一个包,可以用于显示SQL语...
    99+
    2024-04-09
    plsql
  • Oracle如何通过注释改变执行计划
    小编给大家分享一下Oracle如何通过注释改变执行计划,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Oracle 通过注释改变执...
    99+
    2024-04-02
  • Oracle执行计划中 并行和BUFFER SORT的问题
       近日开发说某个系统上有个sql执行时间忽快忽慢,让我帮忙看下,此sql是4个表(2个千万,2个十万)进行inner join操作,最后进行count(*)聚合操作,执行时间1--1...
    99+
    2024-04-02
  • 快速得到SQL带A-Time时间的执行计划的小技巧
    快速得到SQL带A-Time时间的执行计划的小技巧 使用spool把结果输出到文件,然后直接去文件查看执行计划即可 得到带时间的执行计划的方法有两种: 1、在会话设置参数statistics_le...
    99+
    2024-04-02
  • 如何优化MySQL中的循环执行计划
    优化MySQL中的循环执行计划可以通过以下几种方式来实现: 使用合适的索引:确保数据库表中的字段上有适当的索引。索引能够帮助My...
    99+
    2024-04-30
    MySQL
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作