1. 程式人生 > >ORACLE資料庫SQL優化--->如何得到真實的執行計劃

ORACLE資料庫SQL優化--->如何得到真實的執行計劃

在ORACLE資料庫裡通常可以使用如下的四種方法來得到目標SQL的執行計劃:

1,EXPLAIN PLAN命令

2,DBMS_XPLAN包

3,SQLPLUS中的AUTOTRACE開關

4,10046事件

除了第四種方法外,其他的三種方法得到的執行計劃都有可能不準確。在ORACLE資料庫中判斷得到的執行計劃是否準確,就是看目標SQL是否被真正的執行,真正執行過的SQL所對應的執行計劃就是準確的,反之,則有可能不準確。

對於使用第二種方法(DBMS_XPLAN)而言,針對不同的應用場景,你可以選擇如下四種方式的一種。

a, select * from table(dbms_xplan.display)

例如:

SQL> explain plan for select * from hr.employees;

Explained.

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

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1445457117

-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |   107 |  7276 |     3   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| EMPLOYEES |   107 |  7276 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------

8 rows selected.

b,select * from table(dbms_xplan.display_cursor(null,null,'advanced'));

c,select * from table(dbms_xplan.display_cursor('sql_id/hash_value',child_cursor_number,'advanced'));

d,select * from table(dbms_xplan.display_awr('sql_id'));

Note:執行select * from table(dbms_xplan.display)所得到的執行計劃可能是不準確的,因為它只是用於檢視使用explain plan命令得到的目標SQL的執行計劃,目標SQL此時還沒有真正執行,所以用它得到的執行計劃可能不正確。使用剩下的三種方式得到的執行計劃都是準確的,因為此時的目標SQL都已經被實際執行過了。

 對第三種方法(即使用SQLPLUS中的AUTOTRACE)而言,可以有下面幾種方法來開啟:

set autotrace on;(目標SQL都已經被執行)

set autotrace traceonly;(目標SQL都已經被執行)

set autotrace traceonly explain; (對於查詢目標SQL時,是沒有被實際執行,但是如果目標SQL是DML語句時,這個時候DML是實際上已經被執行了)

由於SET AUTOTRACE命令後顯示的執行計劃實際上是來源於呼叫EXPLIAN PLAN命令,而用EXPLAIN PLAN命令得到的執行計劃有可能不準確(特別是在使用了繫結變數的情況下),所以使用SET AUTOTRACE命令所顯示的執行計劃也有可能不準確。

看一個如下的例子來驗證下使用explain plan和set autotrace命令後得到的執行計劃並不是目標SQL真實執行計劃:

SQL> show user
USER is "HR"

SQL> create table T1 as select * from dba_objects;

Table created.

SQL> insert into t1 select * from t1;

50319 rows created.

SQL> commit;

Commit complete.

SQL> insert into t1 select * from t1;

100638 rows created.

SQL> commit;

Commit complete.

SQL> select count(*) from t1;

  COUNT(*)
----------
    201276

 在表T1的OBJECT_ID列上建立一個單鍵值的B樹索引IDX_T1

SQL> create index idx_t1 on t1(object_id);

Index created.

對T1表收集一下統計資訊:

SQL> exec dbms_stats.gather_table_stats(ownname=>'HR',tabname=>'T1',estimate_percent=>100,cascade=>true);

PL/SQL procedure successfully completed.

建立2個繫結變數X和Y,X=0,Y=100000

SQL> var x number;
SQL> var y number;
SQL> exec :x :=0

PL/SQL procedure successfully completed.

SQL> exec :y :=100000

PL/SQL procedure successfully completed.

檢視如下語句的執行計劃:

SQL> explain plan for select count(*) from t1 where object_id between :x and :y;

Explained.

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

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2351893609

-----------------------------------------------------------------------------
| 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_T1 |   503 |  2515 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------


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

   2 - filter(TO_NUMBER(:X)<=TO_NUMBER(:Y))
   3 - access("OBJECT_ID">=TO_NUMBER(:X) AND "OBJECT_ID"<=TO_NUMBER(:Y))

16 rows selected.

從上面可以看出使用EXPLAIN PLAN得到的執行計劃顯示目標SQL走的是對索引IDX_T1的索引範圍掃描

但是實際情況是否是這樣呢?我們實際執行下上面的語句:

SQL> select count(*) from t1 where object_id between :x and :y;

  COUNT(*)
----------
    201276

用DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'ADVANCED')得到目標SQL的真實執行計劃如下所示:

SQL> select * from table(dbms_xplan.display_cursor(null,null,'advanced'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID  9dhu3xk2zu531, child number 0
-------------------------------------
select count(*) from t1 where object_id between :x and :y

Plan hash value: 1410530761

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

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

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------

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

|   0 | SELECT STATEMENT       |        |       |       |   106 (100)|
|

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

|*  2 |   FILTER               |        |       |       |            |

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
|

|*  3 |    INDEX FAST FULL SCAN| IDX_T1|   201K|   982K|   106   (7)| 00:00:02
|

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


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

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------

   1 - SEL$1
   3 - SEL$1 / [email protected]$1

Outline Data
-------------

  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('10.2.0.1')

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      INDEX_FFS(@"SEL$1" "T1"@"SEL$1" ("T1"."OBJECT_ID"))
      END_OUTLINE_DATA
  */

Peeked Binds (identified by position):
--------------------------------------

   1 - :X (NUMBER): 0
   2 - :Y (NUMBER): 100000

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------

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

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

Column Projection Information (identified by operation id):
-----------------------------------------------------------

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

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------


51 rows selected.

從上面的執行計劃可以看出,現在目標SQL實際的執行計劃是走對索引IDX_T1的索引快速全掃描,這才是目標SQL的真實的執行計劃,即剛才用EXLPAIN PLAN命令得到的計劃是不準確的。

我們再來看下,使用SET AUTOTRACE 命令的情況。開啟當前SESSION的AUTOTRACE:

SQL> set autotrace traceonly
SQL> select count(*) from t1 where object_id between :x and :y;


Execution Plan
----------------------------------------------------------
Plan hash value: 2351893609

-----------------------------------------------------------------------------
| 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_T1 |   503 |  2515 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------

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

   2 - filter(TO_NUMBER(:X)<=TO_NUMBER(:Y))
   3 - access("OBJECT_ID">=TO_NUMBER(:X) AND "OBJECT_ID"<=TO_NUMBER(:Y))


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
        451  consistent gets
          0  physical reads
          0  redo size
        413  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

從上面可以看出使用SET AUTOTRACE TRACEONLY後得到的執行計劃和之前用EXPLAIN PLAN命令得到的執行計劃是一樣的。即此時的SET AUTOTRACE TRACEONLY所得到的執行計劃是不準確的。

結論:通過上面的實驗可以證明使用了SET AUTOTRACE命令後顯示的執行計劃實際上是來源於呼叫EXPLAIN PLAN命令,而EXPLAIN PLAN命令所得到的執行計劃可能是不準確的(特別是在繫結變數的時候),索引使用SET AUTORACE命令的所顯示的執行計劃可能是不準確的。

ORACLE資料庫還有如下方法得到真實的執行計劃:

如果是ORACLE 10G及其以上的版本,該SQL的執行計劃又已經被ORACLE捕獲並存儲到了REPOSITORY中,在可以使用AWR SQL報告來得到真實的歷史執行計劃。

相關推薦

ORACLE資料庫SQL優化--->如何得到真實執行計劃

在ORACLE資料庫裡通常可以使用如下的四種方法來得到目標SQL的執行計劃: 1,EXPLAIN PLAN命令 2,DBMS_XPLAN包 3,SQLPLUS中的AUTOTRACE開關 4,10046事件 除了第四種方法外,其他的三種方法得到的執行計劃都有可能不準確。在OR

ORACLE資料庫SQL優化--->如何執行計劃執行順序

建議安裝(10g即以上版本上)xplan package,XPALN包其實是對DBMS_XPLAN包的封裝,使用XPLAN包就可以很清晰的看到執行計劃的執行順序。 安裝很簡單:其中xplan.sql_.txt可以到如下的網站下載: [[email protec

Mysql SQL優化系列之——執行計劃連線方式淺釋

關係庫SQL調優中,雖然思路都是一樣的,具體方法和步驟也是大同小異,但細節卻不容忽視,尤其是執行計劃的具體細節的解讀中,各關係庫確實有區別,特別是mysql資料庫,與其他關係庫的差別更大些,下面,我們僅就SQL執行計劃中最常見的連線方式,做以下簡要介紹和說明。 system : a syst

ORACLE 資料庫 SQL 優化

出處: 1.資料庫訪問優化法則 要正確的優化SQL,我們需要快速定位能性的瓶頸點,也就是說快速找到我們SQL主要的開銷在哪裡?而大多數情況效能最慢的裝置會是瓶頸點,如下載時網路速度可能會是瓶頸點,本地複製檔案時硬碟可能會是瓶頸點,為什麼這些一般的工

崔華基於oracleSQL優化讀書筆記(一)如何得到真實執行計劃

hash mes getting binary oracl only 中文 fun roc ---恢復內容開始--- 得到目標SQL的執行計劃,大致有以下四種方式: 1.explain plan 命令 2.DBMS_XPLAN包 3.SQLPLUS中的autotrace開關

OracleSQL優化專題02-穩固SQL執行計劃的方法

首先構建一個簡單的測試用例來實際演示: create table emp as select * from scott.emp; create table dept as select * from scott.dept; create index idx_emp_empno on emp(empno);

OracleSQL優化專題01-檢視SQL執行計劃的方法

在我2014年總結的“SQL Tuning 基礎概述”中,其實已經介紹了一些檢視SQL執行計劃的方法,但是不夠系統和全面,所以本次SQL優化專題,就首先要系統的介紹一下檢視SQL執行計劃的方法。 本文示例SQL為: --set lines 1000 pages 1000 select a.emp

MySQL資料庫SQL優化第四篇:通過trace分析優化器如何選擇執行計劃

 MySQL5.6提供了對SQL的跟蹤trace,通過trace檔案能夠進一步瞭解為什麼優化器選擇A執行計劃而不是選擇B執行計劃,幫助我們更好地理解優化器行為。     使用方式:首先開啟trace,設定格式為JSON,設定trace最大能夠使用的記憶體大小,避免解析過程中

Oracle效能優化-讀懂執行計劃

Oracle的執行計劃 得到執行計劃的方式 Autotrace例子

SQL和PL/SQL的效能優化之二--執行計劃管理

1、提示--它們僅是建議,優化器可以選擇忽略他們。事實上,優化器將盡可能地遵從優化提示,哪怕會導致空難性的效能影響。一般來說,只有當你用盡非直接方法(收集統計資訊,建立柱狀圖及設定配置引數等)之後,才可以考慮使用提示。     下面是一些更常見的提示:  

ORACLE 查看有多個執行計劃SQL語句

title esc 計劃 有時 pan 轉載 div 通過 ans 轉載自:http://www.cnblogs.com/kerrycode/p/5288030.html ORACLE 查看有多個執行計劃的SQL語句 在SQL優化過程,有時候需要查看哪些S

Oracle之一條SQL對應多個執行計劃

解析:同一個表名對應不同的使用者,對用不同的表結構,就會產生一條SQL產生多個執行計劃。等 分結論4(一條SQL對應多個執行計劃): 一. 關於獲取執行計劃的6種方法和各自區別大家在上一例子中已經大致明白了。     1. explain plan for獲取;      2. set autotrace o

檢視Oracle資料庫SQL執行歷史

方法1:使用LogMiner工具 優點:可以完全挖掘日誌內容,找出所有執行過的SQL語句 缺點: 如果沒有啟用歸檔日誌,則只能對聯機日誌進行挖掘 需要掌握LogMiner的用法 方法2:檢視HIST檢視 優點:簡單,只要使用普通的select語句查

宜信-運維-資料庫|SQL優化:一篇文章說清楚Oracle Hint的正確使用姿勢

一、提示(Hint)概述 1、為什麼引入Hint? Hint是Oracle資料庫中很有特色的一個功能,是很多DBA優化中經常採用的

Oracle 查詢真實執行計劃

什麼是真實執行計劃 獲取Oracle的執行計劃,有幾種方式。(本文使用Oracle 11g XE版本,以及普通使用者scott登入) explain plan for 有兩個步驟: explain plan for ${SQL} select * from table(dbms_xplan.display

轉://從一條巨慢SQL看基於OracleSQL優化

查看 針對性 map 分區 有關 需要 fix pts 大局觀 http://mp.weixin.qq.com/s/DkIPwbDKIjH2FMN13GkT4w 本次分享的內容是基於Oracle的SQL優化,以一條巨慢的SQL為例,從快速解讀SQL執行計劃、如何從執行計劃中

為什麼預估執行計劃真實執行計劃會有差異?

雲和恩墨北區技術project師 專注於 SQL 稽核和優化相關工作。以前服務的客戶涉及金融保險、電信運營商、政府、生產製造等行業。 郭成日 本文由恩墨大講堂154期線上分享整理而成。 一 問題

資料庫SQL優化大總結之 百萬級資料庫面試優化方案

網上關於SQL優化的教程很多,但是比較雜亂。近日有空整理了一下,寫出來跟大家分享一下,其中有錯誤和不足的地方,還請大家糾正補充。 這篇文章我花費了大量的時間查詢資料、修改、排版,希望大家閱讀之後,感覺好的話推薦給更多的人,讓更多的人看到、糾正以及補充。   一、百萬級資料庫優化

53 Oracle資料庫SQL開發之 子查詢——編寫包含子查詢的UPDATE和DELETE

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

66 Oracle資料庫SQL開發之 高階查詢——使用線性迴歸函式

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!