亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Oracle里另外一些典型的執行計劃

發布時間:2020-05-27 00:46:40 來源:網絡 閱讀:930 作者:hbxztc 欄目:關系型數據庫

在之前的文章里寫了Oracle里常見的執行計劃,可以參考文章:http://hbxztc.blog.51cto.com/1587495/1901416,這篇文章里介紹的是其他的一些典型的執行計劃。

1. AND-EQUAL(INDEX MERGE)

AND-EQUAL又稱為INDEX MERGE,顧名思義,INDEX MERGE就是指如果where條件里出現了多個針對不同單列的等值條件,并且這些列上都有單鍵值的索引,則Oracle可能會以相應的單個等值條件去分別掃描這些索引;然后Oracle會合并這些掃描單個索引所得到的rowid集合,如果能從這些集合中找到相同的rowid,那么這個rowid就是目標SQL最終執行結果所對應的rowid。最后,Oracle只需要用這些rowid回表就能得到目標SQL的最終執行結果。

AND-EQUAL在執行計劃中對應的關鍵字就是“AND-EQUAL”,我們可以使用Hint來強制讓Oracle走AND-EQUAL。

看一個實例:

zx@MYDB>create table emp_temp as select * from scott.emp;

Table created.

zx@MYDB>create index idx_mgr on emp_temp(mgr);

Index created.

zx@MYDB>create index idx_deptno on emp_temp(deptno);

Index created.

zx@MYDB>select /*+ and_equal(emp_temp idx_mgr idx_deptno) */ empno,job from emp_temp where mgr=7902 and deptno=20;

     EMPNO JOB
---------- ---------------------------
      7369 CLERK

Oracle里另外一些典型的執行計劃

從上述顯示內容中可以看出,現在此SQL的執行計劃走的是對索引IDX_MGR和IDX_DEPTNO的AND-EQUAL。

2. INDEX JOIN

INDEX JOIN很容易引起誤解,因為它并不是指通常意義上針對多表的表連接。這里INDEX JOIN指的是針對單表上的不同索引之間的連接。

還以上面的EMP_TEMP為例,已經在列MGR和DEPTNO上分別創建了兩個單鍵值的B*Tree索引,如果此時執行SQL語句“select mgr,deptno from emp_temp”,因為這里要查詢的列MGR和DEPTNO均可來源于索引IDX_MGR和IDX_DEPTNO(不考慮NULL值),不用回表,所以除了常規的執行方法之外,Oracle還可以采用如下方法:分別掃描索引IDX_MGR和IDX_DEPTNO,得到的結果集分別記為結果集1和結果集2,然后將結果集1和2做一個連接,連接條件就是“結果集1.rowid=結果集2.rowid”,這樣得到的最終連接結果(不用回表)就是上述SQL的執行結果。

很顯然,針對上述SQL的INDEX JOIN的執行效率是不如我們直接在列MGR和DEPTNO上建一個組合索引,然后直接掃描該組全索引的效率高。INDEX JOIN只是為CBO提供了一種可選的執行路徑,大多數情況下,它只是額外多出的一種選擇而已。

看一下例子:

zx@MYDB>delete from emp_temp where mgr is null;

1 row deleted.

zx@MYDB>commit;

Commit complete.

zx@MYDB>alter table emp_temp modify mgr not null;

Table altered.

zx@MYDB>alter table emp_temp modify deptno not null;

Table altered.

zx@MYDB>select mgr,deptno from emp_temp;

       MGR     DEPTNO
---------- ----------
      7839         10
......
      7698         30

13 rows selected.

Oracle里另外一些典型的執行計劃

從上述顯示內容可以看出,現在目標SQL的執行計劃走的是對索引IDX_MGR和IDX_DEPTNO的HASH JOIN。

3. VIEW

Oracle在處理包含視圖的SQL時,根據該視圖是否能做為視圖合并(View Merging),其對應的執行計劃有如下兩種形式。

  • 如果可以做視圖合并,則Oracle在執行該SQL時可以直接針對該視圖的基表,此時SQL的執行計劃中很可能不會出現關鍵字“VIEW”(不能完全依賴關鍵字“VIEW”的出現與否來判斷Oracle是否做了視圖合并,因為對于某些SQL而言,即使Oracle已經做了視圖合并但其所對應的執行計劃中可能還會顯示關鍵字“VIEW”)。

  • 如果不能做視圖合并,則Oracle將把該視圖看作一個整體并獨立地執行它,此時SQL的執行計劃中將會出現關鍵字“VIEW”。

看一個實例,還是使用上面的EMP_TEMP表:

zx@MYDB>create view emp_mgr_view as select * from emp_temp where job='MANAGER';

View created.

zx@MYDB>select empno,sal from emp_mgr_view where ename='CLARK';

     EMPNO        SAL
---------- ----------
      7782       2450

Oracle里另外一些典型的執行計劃

從上述顯示內容中可以看出,現在SQL的執行計劃走的是對表EMP_TEMP的全表掃描,并且全表掃描進的過濾查詢條件是filter(("ENAME"='CLARK' AND "JOB"='MANAGER')).顯然這里Oracle做了視圖合并,直接查詢的視圖EMP_MGR_VIEW的基表EMP_TEMP,并且把針對視圖的where條件推到了視圖的內部,和原先創建視圖時的限制條件做了合并。

現在修改視圖EMP_MGR_VIEW的定義,其創建語句中加入ROWNUM關鍵字,這樣新創建的同名視圖EMP_MGR_VIEW將不能再做視圖合并:

zx@MYDB>create or replace view emp_mgr_view as select * from emp_temp where job='MANAGER' and rownum<10;

View created.

zx@MYDB>select empno,sal from emp_mgr_view where ename='CLARK';

     EMPNO        SAL
---------- ----------
      7782       2450

Oracle里另外一些典型的執行計劃

從上述顯示內容中可以看出,現在該SQL的執行計劃中包含了關鍵字“VIEW”,即表明這里Oracle并沒有對視圖EMP_MGR_VIEW做視圖合并,視圖EMP_MGR_VIEW被Oracle當作一個整體來獨立執行。

4. FILTER

FILTER直譯過來就是過濾、篩選的意思,它是一種特殊的執行計劃,所對應的執行過程就是如下三步:

得到一個驅動結果集

根據一定的過濾條件從上述驅動結果集中濾除不滿足條件的記錄

結果集中剩下的記錄就會返回給最終用戶或者繼續參與一下個執行步驟。

看一個實例,還是使用上面的視圖EMP_MGR_VIEW:

zx@MYDB>select empno,ename from emp where empno in (select empno from emp_mgr_view);

     EMPNO ENAME
---------- ------------------------------
      7566 JONES
      7698 BLAKE
      7782 CLARK

Oracle里另外一些典型的執行計劃

從上述的顯示內容可以看出,現在該SQL的執行計劃走的是嵌套循環連接,并沒有出現我們希望的FILTER類型的執行計劃。這是因為Oracle在這里做了子查詢展開(Subquery Unnexting),即把子查詢和它外部的SQL做了合并,轉化成視圖VW_NOS_1和表EMP做連接。

這里使用Hint禁掉子查詢展開后重新執行上述SQL:

zx@MYDB>select empno,ename from emp where empno in (select /*+ NO_UNNEST */ empno from emp_mgr_view);

     EMPNO ENAME
---------- ------------------------------
      7566 JONES
      7698 BLAKE
      7782 CLARK

Oracle里另外一些典型的執行計劃

從上述顯示內容中可以看出,現在該SQL走的就是我們希望的FILTER類型執行計劃。

FILTER類型的執行計劃實際上是種改良的嵌套循環連接,它并不像嵌套循環連接那樣,驅動結果集中的有多少記錄就得訪問多少次被驅動表。

用一個實驗驗證:

zx@MYDB>select * from t1;

      COL1 COL2
---------- ----
         1 A
         2 B
         3 B

zx@MYDB>select * from t2;

COL2 COL3
---- ------
A    A2
B    B2
D    D2

zx@MYDB>select /*+ gather_plan_statistics */ * from t1 where col2 in(select /*+ no_unnest */ col2 from t2);

      COL1 COL2
---------- ----
         1 A
         2 B
         3 B

Oracle里另外一些典型的執行計劃

注意到上述顯示內容中id=2的執行步驟所對應的列A-Rows的值為3,id=3的執行步驟所對應的列Starts的值為2,說明雖然全表掃描T1所得到的驅動結果集的數量為3,但走Filter類型的執行計劃時訪問被驅動表T2的實際次數卻不是3,而是2.這是因為表T數量雖然是3,但其列COL2的distinct值的數量卻只有2,所以在用過濾條件“where col2 in(select /*+ no_unnest */ col2 from t2)”去過濾表T1中的數據時,只用訪問兩次表T2就可以了。

5. SORT

SORT就是排序的意思,執行計劃中的SORT通常會以組合的方式出現,這些組合方式包括但不限于如下這幾種:

  • SORT AGGREGATE

  • SORT UNIQUE

  • SORT JOIN

  • SORT GROUP BY 

  • SORT ORDER BY

  • BUFFER SORT

執行計劃中即使出現了關鍵字“SORT”,也不一定意味著就需要排序,比如SORT AGGREGATE和BUFFER SORT就不一定需要排序。

看一個實例,還是使用上面的EMP_TEMP表:

zx@MYDB>set autotrace traceonly
zx@MYDB>select sum(sal) from emp_temp where job='MANAGER';

Oracle里另外一些典型的執行計劃

從上述顯示內容可以看出,現在SQL的執行計劃走的是SORT AGGREGATE,這里執行的SQL只是求了一個sum值,很顯然這里不需要排序的。統計信息中的sort(memroy)和sort(disk)的值均為0,也說明Oracle在執行此SQL時并沒有做任何排序操作,所以我們說SORT AGGREGATE并不一定需要排序,這其中的關鍵字“SORT”具有一定的迷惑性。

下面再做實例:

zx@MYDB>set autotrace off
zx@MYDB>select distinct ename from emp_temp where job='MANAGER' order by ename;

ENAME
------------------------------
BLAKE
CLARK
JONES

上述SQL的含義是既要排序又要去重,它對應的執行計劃就會是SORT UNIQUE

Oracle里另外一些典型的執行計劃

zx@MYDB>select /*+ use_merge(t1 t2) */t1.empno,t1.ename,t2.sal from scott.emp t1,emp_temp t2 where t1.empno=t2.empno;

Oracle里另外一些典型的執行計劃

從上述顯示內容中可以看出,現在該SQL的執行計劃走的是對EMP和EMP_TEMP的排序合并連接。SORT JOIN類型的執行計劃通常會出現在排序合并連接中,它是排序合并連接所對應的執行計劃第一步要做的事情。

再執行如下SQL:

zx@MYDB>select ename from emp_temp where job='MANAGER' order by ename;

ENAME
------------------------------
BLAKE
CLARK
JONES

上述SQL的含義是只需要單純的排序,它對應的執行計劃就會是SORT ORDER BY:

Oracle里另外一些典型的執行計劃

接著執行下面的SQL:

select ename from emp_temp where job='MANAGER' group by ename order by ename;

ENAME
------------------------------
BLAKE
CLARK
JONES

上述SQL的含義是既要排序又要分組,所以它對應的執行計劃就會是SORT GROUP BY:

Oracle里另外一些典型的執行計劃

最后執行如下SQL:

select t1.empno,t2.ename from scott.emp t1,emp_temp t2;

Oracle里另外一些典型的執行計劃

從上述顯示內容可以看出,現在該SQL的執行計劃走的是對表EMP_TEMP和表EMP上主鍵PK_EMP的笛卡兒連接,因為上述SQL中沒有指定連接條件。此處執行計劃的步驟是首先全表掃描表EMP_TEMP,掃描結果記為結果集1;接著對表EMP上的主鍵PK_EMP做索引快速全掃描,并將掃描結果load進PGA中,然后對結果集1和結果集2做笛卡兒連接,最后笛卡兒連接的結果就是上述SQL的最終執行結果。執行計劃中關鍵字“BUFFER SORT”就是表示Oracle會借用PGA并把掃描結果load進去,這樣做的好處是省掉了相應的緩存在SGA中所帶來的種種額外開銷(如持有、釋放相關Latch等)。PGA常常用來做排序,這可能就是“BUFFER SORT”中關鍵字SORT的由來。

需要注意的是,BUFFER SORT不一定會排序,也可能會排序,也可能不會。

看一個SQL是否排序,最直觀的方法就是查看其統計信息中"sorts(memory)"和"sorts(disk)"的值,如果這兩個指標的值大于0,則說明該SQL在執行時經歷過排序。但遺憾的是,這兩個指標對BUFFER SORT而言是不準的,此時我們就需要借助目標SQL真實執行計劃中"Column Projection Information"部分"keys"的值來判斷到底所對應的BUFFER SORT有沒有排序。"#keys"的值就表示該執行步驟實際排序列的數量,如果"#keys"值大于0時,則表示該執行步驟確實排過序了。

看如下SQL:

set autotrace traceonly
zx@MYDB>select t1.ename,t2.loc from scott.emp t1,scott.dept t2;

56 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 2034389985

-----------------------------------------------------------------------------
| Id  | Operation	     | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |	    |	 56 |	784 |	 10   (0)| 00:00:01 |
|   1 |  MERGE JOIN CARTESIAN|	    |	 56 |	784 |	 10   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL  | DEPT |	  4 |	 32 |	  3   (0)| 00:00:01 |
|   3 |   BUFFER SORT	     |	    |	 14 |	 84 |	  7   (0)| 00:00:01 |
|   4 |    TABLE ACCESS FULL | EMP  |	 14 |	 84 |	  2   (0)| 00:00:01 |
-----------------------------------------------------------------------------


Statistics
----------------------------------------------------------
	315  recursive calls
	  0  db block gets
	 70  consistent gets
	 11  physical reads
	  0  redo size
       1831  bytes sent via SQL*Net to client
	557  bytes received via SQL*Net from client
	  5  SQL*Net roundtrips to/from client
	  7  sorts (memory)
	  0  sorts (disk)
	 56  rows processed

注意到上述顯示內容中“統計信息”部分的sorts(memory)的值為7,但由于該SQL中出現了ID=3的執行步驟“BUFFER SORT”,所以這并不一定能說明該SQL在執行時經歷過排序。

我們來看一下執行墳墓中id=3的執行步驟“BUFFER SORT”所對應的“#keys”的值:

zx@MYDB>select sql_id,sql_text from v$sql where sql_text = 'select t1.ename,t2.loc from scott.emp t1,scott.dept t2';

SQL_ID		     SQL_TEXT
-------------------- ----------------------------------------------------------------------------------------------------
3dmxcxk72fwr4	     select t1.ename,t2.loc from scott.emp t1,scott.dept t2

zx@MYDB>select * from table(dbms_xplan.display_cursor('3dmxcxk72fwr4',0,'advanced'));

Oracle里另外一些典型的執行計劃

從上述顯示內容中可以看出,Id=3的執行步驟“BUFFER SORT”所對應的“#keys”的值為0,說明該SQL在執行“BUFFER SORT”時確實沒有排序,排序的數量為0。

這就驗證了我們之前提到的觀點:統計信息中sorts(memory)和sorts(disk)的值對于BUFFER SORT而言是不準的,Oracle在執行BUFFER SORT時可能不需要排序。

6. UNION/UNION ALL

UNION/UNION ALL表示對兩個結果集進行合并,如果它們出現在執行計劃中也表示相同的含義。

UNION和UNION ALL的區別是:UNION ALL僅僅是簡單地將兩個結果集合并,并不做任何額外的處理;而UNION除了將兩個結果集簡單合并之外,還會對合并后的結果集做排序和去重,即UNION相當于先做UNION ALL,然后再對UNION ALL之后的結果集做SORT UNIQUE

看一個實例:

select empno,ename from scott.emp union all select empno,ename from emp_temp;

     EMPNO ENAME
---------- ------------------------------
      7369 SMITH
......
      7934 MILLER

27 rows selected.

Oracle里另外一些典型的執行計劃

從上述顯示內容中可以看出,現在該SQL的執行計劃走的是對表EMP和EMP_TEMP全表掃描后的結果集的UNION ALL,UNION ALL在執行計劃中對應的關鍵字就是UNION-ALL。表EMP有13條記錄,表EMP_TEMP有12條記錄,UNION ALL合并后的結果集總是25。

把UNION ALL改為UNION:

zx@MYDB>select empno,ename from scott.emp union select empno,ename from emp_temp;

     EMPNO ENAME
---------- ------------------------------
      7369 SMITH
......
      7934 MILLER

14 rows selected.

Oracle里另外一些典型的執行計劃

從上述顯示內容可以看出,現在該SQL的執行計劃走的是對EMP和EMP_TEMP全表掃描的結果集的UNION,UNION在執行計劃中對應的關鍵字就是"UNION-ALL"和"SORT UNIQUE",即表示UNION相當于在UNION ALL的基礎上做排序和去重。表EMP_TEMP的數據全部來源于表EMP,所以這里UNION操作返回結果集的復數就是表EMP的行數14。

7. CONCAT

CONCAT就是IN-List擴展(IN-List Expansion)或OR擴展(OR Expansion),IN-List擴展/OR擴展在執行計劃中對應的關鍵字是“CONCATENATION”,使用Hint來強制讓Oracle走IN-List擴展/OR擴展。

看一下實例:

zx@MYDB>select empno,ename from scott.emp where empno in (7654,7698,7782);

     EMPNO ENAME
---------- ------------------------------
      7654 MARTIN
      7698 BLAKE
      7782 CLARK

Oracle里另外一些典型的執行計劃

從上述顯示內容可以看出,現在該SQL的執行計劃走的是對表EMP和主鍵索引PK_EMP的IN-List迭代。

使用Hint讓Oracle強制走IN-List擴展

zx@MYDB>select /*+ USE_CONCAT */empno,ename from scott.emp where empno in (7654,7698,7782);

     EMPNO ENAME
---------- ------------------------------
      7654 MARTIN
      7698 BLAKE
      7782 CLARK

Oracle里另外一些典型的執行計劃

從上面顯示內容可以看出,Hint失效了,還是走IN-List迭代。使用如下兩個事件在當前Session中將IN-List迭代禁掉,并將輸入參數no_invalidate的值設為false后重新收集一下統計信息,以便后續再次執行上述SQL時不會沒用之前走IN-List迭代的執行計劃:

zx@MYDB>alter session set events '10142 trace name context forever';

Session altered.

zx@MYDB>alter session set events '10157 trace name context forever';

Session altered.

zx@MYDB>exec dbms_stats.gather_table_stats(ownname=>'SCOTT',tabname=>'EMP',cascade=>true,method_opt=>'for all columns size 1',no_invalidate=>false);

PL/SQL procedure successfully completed.

zx@MYDB>select /*+ USE_CONCAT */ empno,ename from scott.emp where empno in (7654,7698,7782);

     EMPNO ENAME
---------- ------------------------------
      7654 MARTIN
      7698 BLAKE
      7782 CLARK

Oracle里另外一些典型的執行計劃

從上述顯示內容中可以看出,現在該SQL的執行計劃變成了我們想要的IN-List擴展,在執行計劃中對應的關鍵字就是CONCATENATION。這里CONCATENATION的含義就相當于UNION ALL,即上述SQL就相當于UNION ALL改寫為如下的形式:

select empno,ename from emp where empno=7782

union all

select empno,ename from emp where empno=7698

union all

select empno,ename from emp where empno=7654

8. CONNECT BY

CONNECT BY是Oracle數據庫中層次查詢(Hierachical Queries)所對應的關鍵字,如果出現在執行中也是表示同樣的含義。

看一下實例:

zx@MYDB>select empno,ename,job,mgr from scott.emp;

     EMPNO ENAME			  JOB				     MGR
---------- ------------------------------ --------------------------- ----------
      7369 SMITH			  CLERK 			    7902
      7499 ALLEN			  SALESMAN			    7698
      7521 WARD 			  SALESMAN			    7698
      7566 JONES			  MANAGER			    7839
      7654 MARTIN			  SALESMAN			    7698
      7698 BLAKE			  MANAGER			    7839
      7782 CLARK			  MANAGER			    7839
      7788 SCOTT			  ANALYST			    7566
      7839 KING 			  PRESIDENT
      7844 TURNER			  SALESMAN			    7698
      7876 ADAMS			  CLERK 			    7788
      7900 JAMES			  CLERK 			    7698
      7902 FORD 			  ANALYST			    7566
      7934 MILLER			  CLERK 			    7782

從上述內容可以看到KING是PRESIDENT,它所在記錄的MGR的值為NULL,表示KING沒有上級。

我們執行如下SQL,從KING所在的記錄開始,將所有人按照上下級關系分成顯示出來:

zx@MYDB>select empno,ename,mgr from emp start with empno=7839 connect by prior empno=mgr;

     EMPNO ENAME				 MGR
---------- ------------------------------ ----------
      7839 KING
      7566 JONES				7839
      7788 SCOTT				7566
      7876 ADAMS				7788
      7902 FORD 				7566
      7369 SMITH				7902
      7698 BLAKE				7839
      7499 ALLEN				7698
      7521 WARD 				7698
      7654 MARTIN				7698
      7844 TURNER				7698
      7900 JAMES				7698
      7782 CLARK				7839
      7934 MILLER				7782

查看執行計劃:

Oracle里另外一些典型的執行計劃

從上述顯示內容可以看出,現在該SQL的執行計劃走的就是CONNECT BY,在執行計劃中我們也能看到CONNECT BY 關鍵字。


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

四川省| 香格里拉县| 诸暨市| 通渭县| 微博| 公安县| 桃源县| 响水县| 佳木斯市| 维西| 淳安县| 博爱县| 德化县| 长白| 彰武县| 饶河县| 运城市| 柞水县| 武平县| 广平县| 赤壁市| 绥中县| 会理县| 松原市| 桐柏县| 铁力市| 东阳市| 海南省| 金坛市| 雷州市| 香河县| 合山市| 马龙县| 灯塔市| 长乐市| 潍坊市| 民县| 三原县| 长春市| 聂拉木县| 镇宁|