Oracle Parallel Execution(并行执行) .
關(guān)于Oracle 的并行執(zhí)行,Oracle 官方文檔有詳細(xì)的說明:
??????????????????????????????? Using Parallel Execution
http://download.oracle.com/docs/cd/E11882_01/server.112/e10837/parallel.htm#VLDBG010
This chapter covers tuning in a parallel execution environment and discusses the following topics:
·???????? Introduction to Parallel Execution
·???????? How Parallel Execution Works
·???????? Types of Parallelism
·???????? Initializing and Tuning Parameters for Parallel Execution
·???????? Tuning General Parameters for Parallel Execution
·???????? Monitoring Parallel Execution Performance
·???????? Miscellaneous Parallel Execution Tuning Tips
?
一.???? 并行(Parallel)和OLAP系統(tǒng)
并行的實(shí)現(xiàn)機(jī)制是: 首先,Oracle 會(huì)創(chuàng)建一個(gè)進(jìn)程用于協(xié)調(diào)并行服務(wù)進(jìn)程之間的信息傳遞,這個(gè)協(xié)調(diào)進(jìn)程將需要操作的數(shù)據(jù)集(比如表的數(shù)據(jù)塊)分割成很多部分,稱為并行處理單元,然后并行協(xié)調(diào)進(jìn)程給每個(gè)并行進(jìn)程分配一個(gè)數(shù)據(jù)單元。比如有四個(gè)并行服務(wù)進(jìn)程,他們就會(huì)同時(shí)處理各自分配的單元,當(dāng)一個(gè)并行服務(wù)進(jìn)程處理完畢后,協(xié)調(diào)進(jìn)程就會(huì)給它們分配另外的單元,如此反復(fù),直到表上的數(shù)據(jù)都處理完畢,最后協(xié)調(diào)進(jìn)程負(fù)責(zé)將每個(gè)小的集合合并為一個(gè)大集合作為最終的執(zhí)行結(jié)果,返回給用戶。
?
并行處理的機(jī)制實(shí)際上就是把一個(gè)要掃描的數(shù)據(jù)集分成很多小數(shù)據(jù)集,Oracle 會(huì)啟動(dòng)幾個(gè)并行服務(wù)進(jìn)程同時(shí)處理這些小數(shù)據(jù)集,最后將這些結(jié)果匯總,作為最終的處理結(jié)果返回給用戶。
?
這種數(shù)據(jù)并行處理方式在OLAP系統(tǒng)中非常有用,OLAP系統(tǒng)的表通常來說都是非常大,如果系統(tǒng)的CPU比較多,讓所有的CPU共同來處理這些數(shù)據(jù),效果就會(huì)比串行執(zhí)行要高的多。
?
然而對(duì)于OLTP系統(tǒng),通常來講,并行并不合適,原因是OLTP系統(tǒng)上幾乎在所有的SQL操作中,數(shù)據(jù)訪問路勁基本上以索引訪問為主,并且返回結(jié)果集非常小,這樣的SQL 操作的處理速度一般非常快,不需要啟用并行。
?
?
二. 并行處理的機(jī)制
??????????????? 當(dāng)Oracle 數(shù)據(jù)庫啟動(dòng)的時(shí)候,實(shí)例會(huì)根據(jù)初始化參數(shù):
??????????????????????????????? PARALLEL_MIN_SERVERS=n
??????????????? 的值來預(yù)先分配n個(gè)并行服務(wù)進(jìn)程,當(dāng)一條SQL 被CBO判斷為需要并行執(zhí)行時(shí)發(fā)出SQL的會(huì)話進(jìn)程變成并行協(xié)助進(jìn)程,它按照并行執(zhí)行度的值來分配進(jìn)程服務(wù)器進(jìn)程。
?
??????????????? 首先協(xié)調(diào)進(jìn)程會(huì)使用ORACLE 啟動(dòng)時(shí)根據(jù)參數(shù): parallel_min_servers=n的值啟動(dòng)相應(yīng)的并行服務(wù)進(jìn)程,如果啟動(dòng)的并行服務(wù)器進(jìn)程數(shù)不足以滿足并行度要求的并行服務(wù)進(jìn)程數(shù),則并行協(xié)調(diào)進(jìn)程將額外啟動(dòng)并行服務(wù)進(jìn)程以提供更多的并行服務(wù)進(jìn)程來滿足執(zhí)行的需求。 然后星星協(xié)調(diào)進(jìn)程將要處理的對(duì)象劃分成小數(shù)據(jù)片,分給并行服務(wù)進(jìn)程處理;并行服務(wù)進(jìn)程處理完畢后將結(jié)果發(fā)送給并行協(xié)調(diào)進(jìn)程,然后由并行協(xié)調(diào)進(jìn)程將處理結(jié)果匯總并發(fā)送給用戶。
?
??????????????? 剛才講述的是一個(gè)并行處理的基本流程。 實(shí)際上,在一個(gè)并行執(zhí)行的過程中,還存在著并行服務(wù)進(jìn)程之間的通信問題。
??????????????? 在一個(gè)并行服務(wù)進(jìn)程需要做兩件事情的時(shí)候,它會(huì)再啟用一個(gè)進(jìn)程來配和當(dāng)前的進(jìn)程完成一個(gè)工作,比如這樣的一條SQL語句:
??????????????? Select * from employees order by last_name;
???????????????
??????????????? 假設(shè)employees表中l(wèi)ast_name 列上沒有索引,并且并行度為4,此時(shí)并行協(xié)調(diào)進(jìn)程會(huì)分配4個(gè)并行服務(wù)進(jìn)程對(duì)表employees進(jìn)行全表掃描操作,因?yàn)樾枰獙?duì)結(jié)果集進(jìn)行排序,所以并行協(xié)調(diào)進(jìn)程會(huì)額外啟用4個(gè)并行服務(wù)進(jìn)程,用于處理4個(gè)進(jìn)程傳送過來的數(shù)據(jù),這新啟用的用戶處理傳遞過來數(shù)據(jù)的進(jìn)程稱為父進(jìn)程,用戶傳出數(shù)據(jù)(最初的4個(gè)并行服務(wù)進(jìn)程)成為子進(jìn)程,這樣整個(gè)并行處理過程就啟用了8個(gè)并行服務(wù)進(jìn)程。 其中每個(gè)單獨(dú)的并行服務(wù)進(jìn)程的行為叫作并行的內(nèi)部操作,而并行服務(wù)進(jìn)程之間的數(shù)據(jù)交流叫做并行的交互操作。
??????????????? 這也是有時(shí)我們發(fā)現(xiàn)并行服務(wù)進(jìn)程數(shù)量是并行度的2倍,就是因?yàn)閱?dòng)了并行服務(wù)父進(jìn)程操作的緣故。
?
?
三. 讀懂一個(gè)并行處理的執(zhí)行計(jì)劃
?
CREATE TABLE emp2 AS SELECT * FROM employees;
ALTER TABLE emp2 PARALLEL 2;
?
EXPLAIN PLAN FOR
? SELECT SUM(salary) FROM emp2 GROUP BY department_id;
SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());
?
--------------------------------------------------------------------------------------------------------
| Id? | Operation??????????????? | Name???? | Rows? | Bytes | Cost (%CPU) |??? TQ? |IN-OUT| PQ Distrib |
--------------------------------------------------------------------------------------------------------
|?? 0 | SELECT STATEMENT? ???????|????????? |?? 107 |? 2782 |???? 3 (34)? |??????? |????? |??????????? |
|?? 1 |? PX COORDINATOR????????? |????????? |?????? |?????? |???????????? |??????? |????? |??????????? |
|?? 2 |?? PX SEND QC (RANDOM)??? | :TQ10001 |?? 107 |? 2782 |???? 3 (34)? |? Q1,01 | P->S | QC (RAND)? |
|?? 3 |??? HASH GROUP BY???????? |????????? |?? 107 |? 2782 |???? 3 (34)? |? Q1,01 | PCWP |??????????? |
|?? 4 |???? PX RECEIVE?????????? |????????? |?? 107 |? 2782 |???? 3 (34)? |? Q1,01 | PCWP |??????????? |
|?? 5 |????? PX SEND HASH?????? ?| :TQ10000 |?? 107 |? 2782 |???? 3 (34)? |? Q1,00 | P->P | HASH?????? |
|?? 6 |?????? HASH GROUP BY????? |????????? |?? 107 |? 2782 |???? 3 (34)? |? Q1,00 | PCWP |??????????? |
|?? 7 |????? ??PX BLOCK ITERATOR |? ????????|?? 107 |? 2782 |???? 2 (0)?? |? Q1,00 | PCWP |??????????? |
|?? 8 |???????? TABLE ACCESS FULL| EMP2???? |?? 107 |? 2782 |???? 2 (0)?? |? Q1,00 | PCWP |??????????? |
--------------------------------------------------------------------------------------------------------
?
The table EMP2 is scanned in parallel by one set of slaves while the aggregation for the GROUP BY is done by the second set. The PX BLOCK ITERATOR row source represents the splitting up of the table EMP2 into pieces so as to divide the scan workload between the parallel scan slaves. The PX SEND and PX RECEIVE row sources represent the pipe that connects the two slave sets as rows flow up from the parallel scan, get repartitioned through the HASH table queue, and then read by and aggregated on the top slave set. The PX SEND QC row source represents the aggregated values being sent to the QC in random (RAND) order. The PX COORDINATOR row source represents the QC or Query Coordinator which controls and schedules the parallel plan appearing below it in the plan tree.
?
??????????????? 上面這段文字是從Oracle 聯(lián)機(jī)文檔上蕩下來的。
http://download.oracle.com/docs/cd/E11882_01/server.112/e10821/ex_plan.htm#PFGRF94687
?
通過執(zhí)行計(jì)劃,我們來看一下它的執(zhí)行步驟:
??????????????? (1)并行服務(wù)進(jìn)程對(duì)EMP2表進(jìn)行全表掃描。
??????????????? (2)并行服務(wù)進(jìn)程以ITERATOR(迭代)方式訪問數(shù)據(jù)塊,也就是并行協(xié)調(diào)進(jìn)程分給每個(gè)并行服務(wù)進(jìn)程一個(gè)數(shù)據(jù)片,在這個(gè)數(shù)據(jù)片上,并行服務(wù)進(jìn)程順序地訪問每個(gè)數(shù)據(jù)塊(Iterator),所有的并行服務(wù)進(jìn)程將掃描的數(shù)據(jù)塊傳給另一組并行服務(wù)進(jìn)程(父進(jìn)程)用于做Hash Group操作。
??????????????? (3)并行服務(wù)父進(jìn)程對(duì)子進(jìn)程傳遞過來的數(shù)據(jù)做Hash Group操作。
??????????????? (4)并行服務(wù)進(jìn)程(子進(jìn)程)將處理完的數(shù)據(jù)發(fā)送出去。
??????????????? (5)并行服務(wù)進(jìn)程(父進(jìn)程)接收到處理過的數(shù)據(jù)。
??????????????? (6)合并處理過的數(shù)據(jù),按照隨即的順序發(fā)給并行協(xié)調(diào)進(jìn)程(QC:Query Conordinator)。
??????????????? (7)并行協(xié)調(diào)進(jìn)程將處理結(jié)果發(fā)給用戶。
?
當(dāng)使用了并行執(zhí)行,SQL的執(zhí)行計(jì)劃中就會(huì)多出一列:in-out。 該列幫助我們理解數(shù)據(jù)流的執(zhí)行方法。 它的一些值的含義如下:
Parallel to Serial(P->S): 表示一個(gè)并行操作發(fā)送數(shù)據(jù)給一個(gè)串行操作,通常是并行incheng將數(shù)據(jù)發(fā)送給并行調(diào)度進(jìn)程。
Parallel to Parallel(P->P):表示一個(gè)并行操作向另一個(gè)并行操作發(fā)送數(shù)據(jù),疆場(chǎng)是兩個(gè)從屬進(jìn)程之間的數(shù)據(jù)交流。
Parallel Combined with parent(PCWP): 同一個(gè)從屬進(jìn)程執(zhí)行的并行操作,同時(shí)父操作也是并行的。
Parallel Combined with Child(PCWC): 同一個(gè)從屬進(jìn)程執(zhí)行的并行操作,子操作也是并行的。
Serial to Parallel(S->P): 一個(gè)串行操作發(fā)送數(shù)據(jù)給并行操作,如果select 部分是串行操作,就會(huì)出現(xiàn)這個(gè)情況。
?
?
四.并行執(zhí)行等待事件
??????????????? 在做并行執(zhí)行方面的性能優(yōu)化的時(shí)候,可能會(huì)遇到如下等待時(shí)間:
??????????????????????????????? PX Deq Credit: send blkd
??????????????? 這是一個(gè)有并行環(huán)境的數(shù)據(jù)庫中,從statspack 或者AWR中經(jīng)常可以看到的等待事件。 在Oracle 9i 里面, 這個(gè)等待時(shí)間被列入空閑等待。 關(guān)于等待時(shí)間參考:
??????????????? Oracle 常見的33個(gè)等待事件
??????????????? http://blog.csdn.net/tianlesoftware/archive/2010/08/12/5807800.aspx
?
一般來說空閑等待可以忽略它,但是實(shí)際上空閑等待也是需要關(guān)注的,因?yàn)橐粋€(gè)空閑的等待,它反映的是另外的資源已經(jīng)超負(fù)荷運(yùn)行了。 基于這個(gè)原因,在Oracle 10g里已經(jīng)把PX Deq Credit: send blkd等待時(shí)間不在視為空閑等待,而是列入了Others 等待事件范圍。
?
PX Deq Credit: send blkd 等待事件的意思是: 當(dāng)并行服務(wù)進(jìn)程向并行協(xié)調(diào)進(jìn)程QC(也可能是上一層的并行服務(wù)進(jìn)程)發(fā)送消息時(shí),同一時(shí)間只有一個(gè)并行服務(wù)進(jìn)程可以向上層進(jìn)程發(fā)送消息,這時(shí)候如果有其他的并行服務(wù)進(jìn)程也要發(fā)送消息,就只能等待了。 知道獲得一個(gè)發(fā)送消息的信用信息(Credit),這時(shí)候會(huì)觸發(fā)這個(gè)等待事件,這個(gè)等待事件的超時(shí)時(shí)間為2秒鐘。
?
??????????????? 如果我們啟動(dòng)了太多的并行進(jìn)程,實(shí)際上系統(tǒng)資源(CPU)或者QC 無法即時(shí)處理并行服務(wù)發(fā)送的數(shù)據(jù),那么等待將不可避免。 對(duì)于這種情況,我們就需要降低并行處理的并行度。
?
??????????????? 當(dāng)出現(xiàn)PX Deq Credit:send blkd等待的時(shí)間很長時(shí),我們可以通過平均等待時(shí)間來判斷等待事件是不是下層的并行服務(wù)進(jìn)程空閑造成的。該等待事件的超時(shí)時(shí)間是2秒,如果平均等待時(shí)間也差不多是2秒,就說明是下層的并行進(jìn)程“無事所做”,處于空閑狀態(tài)。 如果和2秒的差距很大,就說明不是下層并行服務(wù)超時(shí)導(dǎo)致的空閑等待,而是并行服務(wù)之間的競(jìng)爭(zhēng)導(dǎo)致的,因?yàn)檫@個(gè)平均等待事件非常短,說明并行服務(wù)進(jìn)程在很短時(shí)間的等待之后就可以獲取資源來處理數(shù)據(jù)。
所以對(duì)于非下層的并行進(jìn)程造成的等待,解決的方法就是降低每個(gè)并行執(zhí)行的并行度,比如對(duì)象(表,索引)上預(yù)設(shè)的并行度或者查詢Hint 指定的并行度。
?
?
五. 并行執(zhí)行的使用范圍
Oracle的并行技術(shù)在下面的場(chǎng)景中可以使用:
(1)?????? Parallel Query(并行查詢)
(2)?????? Parallel DDL(并行DDL操作,如建表,建索引等)
(3)?????? Parallel DML(并行DML操作,如insert,update,delete等)
?
5.1 并行查詢
??????????????? 并行查詢可以在查詢語句,子查詢語句中使用,但是不可以使用在一個(gè)遠(yuǎn)程引用的對(duì)象上(如DBLINK)。
?
??????????????? 一個(gè)查詢能夠并行執(zhí)行,需要滿足一下條件:
(1)?????? SQL語句中有Hint提示,比如Parallel 或者 Parallel_index.
(2)?????? SQL語句中引用的對(duì)象被設(shè)置了并行屬性。
(3)?????? 多表關(guān)聯(lián)中,至少有一個(gè)表執(zhí)行全表掃描(Full table scan)或者跨分區(qū)的Index range SCAN。
?
如: select? /*+parallel(t 4) * from t;
?
5.2 并行DDL 操作
?
5.2.1 表操作的并行執(zhí)行
??????????????? 以下表操作可以使用并行執(zhí)行:
CREATE TABLE … AS SELECT
?????? ALTER TABLE … move partition
?????? Alter table … split partition
?????? Alter table … coalesce partition
?
DDL操作,我們可以通過trace 文件來查看它的執(zhí)行過程。
?
示例:
?
查看當(dāng)前的trace 文件:
/* Formatted on 2010/8/31 23:33:00 (QP5 v5.115.810.9015) */
SELECT????? u_dump.VALUE
???????? || '/'
???????? || db_name.VALUE
???????? || '_ora_'
???????? || v$process.spid
???????? || NVL2 (v$process.traceid, '_' || v$process.traceid, NULL)
???????? || '.trc'
??????????? "Trace File"
? FROM??????????? v$parameter u_dump
?????????????? CROSS JOIN
????????????????? v$parameter db_name
??????????? CROSS JOIN
?????????????? v$process
???????? JOIN
??????????? v$session
???????? ON v$process.addr = v$session.paddr
?WHERE?????? u_dump.name = 'user_dump_dest'
???????? AND db_name.name = 'db_name'
???????? AND v$session.audsid = SYS_CONTEXT ('userenv', 'sessionid');
?
Trace File
------------------------------------------------------------------------------
d:/app/administrator/diag/rdbms/orcl/orcl/trace/orcl_ora_5836.trc
d:/app/administrator/diag/rdbms/orcl/orcl/trace/orcl_ora_3048.trc
?
SQL> alter session set events '10046 trace name context forever,level 12';
會(huì)話已更改。
SQL> create table 懷寧 parallel 4 as select * from dba_objects;
表已創(chuàng)建。
SQL> alter session set events '10046 trace name context off' ;
會(huì)話已更改。
?
這里用到了ORACLE的event 時(shí)間。 10046事件是用來跟蹤SQL語句的。開啟事件后,相關(guān)的信息會(huì)寫道trace 文件中,這也是之前我們查看trace 文件名的原因。 關(guān)于event事件,參考我的blog:
??????????????? Oracle 跟蹤事件 set event
??????????????? http://blog.csdn.net/tianlesoftware/archive/2009/12/13/4977827.aspx
?
有了trace文件, 我們可以用tkprof 工具,來查看trace 文件的內(nèi)容。 關(guān)于tkprof 工具介紹,參考blog:
??????????????? 使用 Tkprof 分析 ORACLE 跟蹤文件
??????????????? http://blog.csdn.net/tianlesoftware/archive/2010/05/29/5632003.aspx
?
?
進(jìn)入trace 目錄,用tkprof命令生成txt 文件,然后查看txt 文件。
d:/app/Administrator/diag/rdbms/orcl/orcl/trace>tkprof orcl_ora_3048.trc 安慶.txt sys=no
TKPROF: Release 11.2.0.1.0 - Development on 星期二 8月 31 23:45:25 2010
Copyright (c) 1982, 2009, Oracle and/or its affiliates.? All rights reserved.
d:/app/Administrator/diag/rdbms/orcl/orcl/trace>
?
?
5.2.2 創(chuàng)建索引的并行執(zhí)行
??????????????? 創(chuàng)建索引時(shí)使用并行方式在系統(tǒng)資源充足的時(shí)候會(huì)使性能得到很大的提高,特別是在OLAP系統(tǒng)上對(duì)一些很大的表創(chuàng)建索引時(shí)更是如此。 以下的創(chuàng)建和更改索引的操作都可以使用并行:
??????????????? Create index
??????????????? Alter index … rebuild
??????????????? Alter index … rebuild partition
??????????????? Alter index … split partition
?
一個(gè)簡(jiǎn)單的語法:create index t_ind on t(id) parallel 4;
?
監(jiān)控這個(gè)過程和5.2.1 中表一樣,需要通過10046事件。 這里就不多說了。
?
有關(guān)減少創(chuàng)建時(shí)間方法,參考blog:
??????????????? 如何加快建 index 索引 的時(shí)間
??????????????? http://blog.csdn.net/tianlesoftware/archive/2010/07/11/5664019.aspx
?
?
總結(jié):
使用并行方式,不論是創(chuàng)建表,修改表,創(chuàng)建索引,重建索引,他們的機(jī)制都是一樣的,那就是Oracle 給每個(gè)并行服務(wù)進(jìn)程分配一塊空間,每個(gè)進(jìn)程在自己的空間里處理數(shù)據(jù),最后將處理完畢的數(shù)據(jù)匯總,完成SQL的操作。
?
?
5.3 并行DML 操作
??????????????? Oracle 可以對(duì)DML操作使用并行執(zhí)行,但是有很多限制。 如果我們要讓DML 操作使用并行執(zhí)行,必須顯示地在會(huì)話里執(zhí)行如下命令:
??????????????? SQL> alter session enable parallel dml;
會(huì)話已更改。
?
??????????????? 只有執(zhí)行了這個(gè)操作,Oracle 才會(huì)對(duì)之后符合并行條件的DML操作并行執(zhí)行,如果沒有這個(gè)設(shè)定,即使SQL中指定了并行執(zhí)行,Oracle也會(huì)忽略它。
?
5.3.1 delete,update和merge 操作
??????????????? Oracle 對(duì)Delete,update,merge的操作限制在,只有操作的對(duì)象是分區(qū)表示,Oracle 才會(huì)啟動(dòng)并行操作。原因在于,對(duì)于分區(qū)表,Oracle 會(huì)對(duì)每個(gè)分區(qū)啟用一個(gè)并行服務(wù)進(jìn)程同時(shí)進(jìn)行數(shù)據(jù)處理,這對(duì)于非分區(qū)表來說是沒有意義的。
?
5.3.2 Insert 的并行操作
??????????????? 實(shí)際上只有對(duì)于insert into … select … 這樣的SQL語句啟用并行才有意義。 對(duì)于insert into .. values… 并行沒有意義,因?yàn)檫@條語句本身就是一個(gè)單條記錄的操作。
?
??????????????? Insert 并行常用的語法是:
??????????????????????????????? Insert /*+parallel(t 2) */ into t select /*+parallel(t1 2) */ * from t1;
?
??????????????? 這條SQL 語句中,可以讓兩個(gè)操作insert 和select 分別使用并行,這兩個(gè)并行是相互獨(dú)立,互補(bǔ)干涉的,也可以單獨(dú)使用其中的一個(gè)并行。
?
?
六. 并行執(zhí)行的設(shè)定
?
6.1 并行相關(guān)的初始話參數(shù)
?
6.1.1 parallel_min_servers=n
??????????????? 在初始化參數(shù)中設(shè)置了這個(gè)值,Oracle 在啟動(dòng)的時(shí)候就會(huì)預(yù)先啟動(dòng)N個(gè)并行服務(wù)進(jìn)程,當(dāng)SQL執(zhí)行并行操作時(shí),并行協(xié)調(diào)進(jìn)程首先根據(jù)并行度的值,在當(dāng)前已經(jīng)啟動(dòng)的并行服務(wù)中條用n個(gè)并行服務(wù)進(jìn)程,當(dāng)并行度大于n時(shí),Oracle將啟動(dòng)額外的并行服務(wù)進(jìn)程以滿足并行度要求的并行服務(wù)進(jìn)程數(shù)量。
?
6.1.2 parallel_max_servers=n
??????????????? 如果并行度的值大于parallel_min_servers或者當(dāng)前可用的并行服務(wù)進(jìn)程不能滿足SQL的并行執(zhí)行要求,Oracle將額外創(chuàng)建新的并行服務(wù)進(jìn)程,當(dāng)前實(shí)例總共啟動(dòng)的并行服務(wù)進(jìn)程不能超過這個(gè)參數(shù)的設(shè)定值。
?
6.1.3 parallel_adaptive_multi_user=true|false
??????????????? Oracle 10g R2下,并行執(zhí)行默認(rèn)是啟用的。 這個(gè)參數(shù)的默認(rèn)值為true,它讓Oracle根據(jù)SQL執(zhí)行時(shí)系統(tǒng)的負(fù)載情況,動(dòng)態(tài)地調(diào)整SQL的并行度,以取得最好的SQL??? 執(zhí)行性能。
?
6.1.4 parallel_min_percent
??????????????? 這個(gè)參數(shù)指定并行執(zhí)行時(shí),申請(qǐng)并行服務(wù)進(jìn)程的最小值,它是一個(gè)百分比,比如我們?cè)O(shè)定這個(gè)值為50. 當(dāng)一個(gè)SQL需要申請(qǐng)20個(gè)并行進(jìn)程時(shí),如果當(dāng)前并行服務(wù)進(jìn)程不足,按照這個(gè)參數(shù)的要求,這個(gè)SQL比如申請(qǐng)到20*50%=10個(gè)并行服務(wù)進(jìn)程,如果不能夠申請(qǐng)到這個(gè)數(shù)量的并行服務(wù),SQL 將報(bào)出一個(gè)ORA-12827的錯(cuò)誤。
??????????????? 當(dāng)這個(gè)值設(shè)為Null時(shí),表示所有的SQL在做并行執(zhí)行時(shí),至少要獲得兩個(gè)并行服務(wù)進(jìn)程。
?
?
6.2 并行度的設(shè)定
??????????????? 并行度可以通過以下三種方式來設(shè)定:
(1)使用Hint 指定并行度。
(2)使用alter session force parallel 設(shè)定并行度。
(3)使用SQL中引用的表或者索引上設(shè)定的并行度,原則上Oracle 使用這些對(duì)象中并行度最高的那個(gè)值作為當(dāng)前執(zhí)行的并行度。
?
?
示例:
??????????????? SQL>Select /*+parallel(t 4) */ count(*) from t;
??????????????? SQL>Alter table t parallel 4;
??????????????? SQL>Alter session force parallel query parallel 4;
?
Oracle 默認(rèn)并行度計(jì)算方式:
(1)Oracle 根據(jù)CPU的個(gè)數(shù),RAC實(shí)例的個(gè)數(shù)以及參數(shù)parallel_threads_per_cpu的值,計(jì)算出一個(gè)并行度。
(2)對(duì)于并行訪問分區(qū)操作,取需要訪問的分區(qū)數(shù)為并行度。
?
并行度的優(yōu)先級(jí)別從高到低:
??????????????? Hint->alter session force parallel->表,索引上的設(shè)定-> 系統(tǒng)參數(shù)
?
?
實(shí)際上,并行只有才系統(tǒng)資源比較充足的情況下,才會(huì)取得很好的性能,如果系統(tǒng)負(fù)擔(dān)很重,不恰當(dāng)?shù)脑O(shè)置并行,反而會(huì)使性能大幅下降。
?
?
七. 直接加載
??????????????? 在執(zhí)行數(shù)據(jù)插入或者數(shù)據(jù)加載的時(shí)候,可以通過append hint的方式進(jìn)行數(shù)據(jù)的直接加載。
?
在insert 的SQL中使用APPEND,如:
??????????????????????????????? Insert /*+append */ into t select * from t1;
???????????????
還可以在SQL*LOADER里面使用直接加載:
?????? Sqlldr userid=user/pwd control=load.ctl direct=true
?
Oracle 執(zhí)行直接加載時(shí),數(shù)據(jù)直接追加到數(shù)據(jù)段的最后,不需要花費(fèi)時(shí)間在段中需找空間,數(shù)據(jù)不經(jīng)過data buffer直接寫到數(shù)據(jù)文件中,效率要比傳統(tǒng)的加載方式高。
?
示例:
SQL> create table t as select * from user_tables;
表已創(chuàng)建。
SQL> select segment_name,extent_id,bytes from user_extents where segment_name='T';
SEGMENT_NA? EXTENT_ID????? BYTES
---------- ---------- ----------
T?????????????????? 0????? 65536
T?????????????????? 1????? 65536
T?????????????????? 2????? 65536
T?????????????????? 3????? 65536
T??????????? ???????4????? 65536
?
這里我們創(chuàng)建了一張表,分配了5個(gè)extents。
?
SQL> delete from t;
已刪除979行。
SQL> select segment_name,extent_id,bytes from user_extents where segment_name='T';
SEGMENT_NA? EXTENT_ID????? BYTES
---------- ---------- ----------
T?????????????????? 0????? 65536
T?????????????????? 1????? 65536
T?????????????????? 2????? 65536
T?????????????????? 3????? 65536
T?????????????????? 4????? 65536
?
這里刪除了表里的數(shù)據(jù),但是查詢,依然占據(jù)5個(gè)extents。因?yàn)閐elete不會(huì)收縮表空間,不能降低高水位。
?
SQL> insert into t select * from user_tables;
已創(chuàng)建980行。
SQL> commit;
提交完成。
?
SQL> select segment_name,extent_id,bytes from user_extents where segment_name='T';
SEGMENT_NA? EXTENT_ID????? BYTES
---------- ---------- ----------
T?????????????????? 0????? 65536
T?????????????????? 1????? 65536
T?????????????????? 2????? 65536
T?????????????????? 3????? 65536
T?????????????????? 4????? 65536
?
用傳統(tǒng)方式插入,數(shù)據(jù)被分配到已有的空閑空間里。
?
?
SQL> delete from t;
已刪除980行。
SQL> commit;
提交完成。
SQL> select segment_name,extent_id,bytes from user_extents where segment_name='T';
SEGMENT_NA? EXTENT_ID????? BYTES
---------- ---------- ----------
T?????????????????? 0????? 65536
T?????????????????? 1????? 65536
T?????????????????? 2????? 65536
T?????????????????? 3????? 65536
T?????????????????? 4????? 65536
?
刪除數(shù)據(jù),用append直接插入看一下。
?
SQL> insert /*+append */ into t select * from user_tables;
已創(chuàng)建980行。
SQL> commit;
提交完成。
SQL> select segment_name,extent_id,bytes from user_extents where segment_name='T';
SEGMENT_NA? EXTENT_ID????? BYTES
---------- ---------- ----------
T?????????????????? 0????? 65536
T?????????????????? 1????? 65536
T?????????????????? 2????? 65536
T?????????????????? 3????? 65536
T?????? ????????????4????? 65536
T?????????????????? 5????? 65536
T?????????????????? 6????? 65536
T?????????????????? 7????? 65536
T?????????????????? 8????? 65536
T?????????????????? 9????? 65536
已選擇10行。
?
從結(jié)果可以看出,直接加載方式時(shí),雖然表中有很多空的數(shù)據(jù)塊,Oracle 仍然會(huì)額外的分配4個(gè)extent用于直接加載數(shù)據(jù)。
??????????????? 直接加載的數(shù)據(jù)放在表的高水位(High water Mark:hwm)以上,當(dāng)直接加載完成后,Oracle 將表的高水位線移到新加入的數(shù)據(jù)之后,這樣新的數(shù)據(jù)就可以被用戶使用了。
?
Oracle 高水位(HWM)
http://blog.csdn.net/tianlesoftware/archive/2009/10/22/4707900.aspx
?
?
7.1 直接加載和REDO
??????????????? 直接加載在logging模式下,與傳統(tǒng)加載方式產(chǎn)生的redo 日志差別不大,因?yàn)楫?dāng)一個(gè)表有l(wèi)ogging屬性時(shí),即使使用直接加載,所有改變的數(shù)據(jù)依然要產(chǎn)生redo,實(shí)際上是所有修改的數(shù)據(jù)塊全部記錄redo,以便于以后的恢復(fù),這時(shí)候直接加載并沒有太大的優(yōu)勢(shì)。
?
??????????????? 直接加載最常見的是和nologging一起使用,這時(shí)候可以有效地減少redo 的生成量。 注意的是,在這種情況下,直接加載的數(shù)據(jù)塊是不產(chǎn)生redo的,只有一些其他改變的數(shù)據(jù)產(chǎn)生一些redo,比如表空間分配需要修改字典表或者修改段頭數(shù)據(jù)塊,這些修改會(huì)產(chǎn)生少量的redo。
?
??????????????? 實(shí)際上,對(duì)于nologging 方式的直接加載,undo 的數(shù)據(jù)量也產(chǎn)生的很少,因?yàn)橹苯蛹虞d的數(shù)據(jù)并不會(huì)在回滾段中記錄,這些記錄位于高水位之上,在事務(wù)提交之前,對(duì)于其他用戶來說是不可見的,所以不需要產(chǎn)生undo,事務(wù)提交時(shí),Oracle 將表的高水位線移到新的數(shù)據(jù)之后,如果事務(wù)回滾,只需要保持高水位線不動(dòng)即可,就好像什么都沒有發(fā)生一樣。
?
??????????????? 注意,由于在nologging模式下,redo 不記錄數(shù)據(jù)修改的信息,所以直接加載完后,需要立即進(jìn)行相關(guān)的備份操作,因?yàn)檫@些數(shù)據(jù)沒有記錄在歸檔日志中,一旦數(shù)據(jù)損壞,只能用備份來恢復(fù),而不能使用歸檔恢復(fù)。
?
Logging模式下示例:
SQL> set autot trace stat;
SQL> insert /*+append */ into t select * from user_tables;
已創(chuàng)建980行。
統(tǒng)計(jì)信息
----------------------------------------------------------
??????? 132? recursive calls
???????? 87? db block gets
?????? 8967? consistent gets
????????? 0? physical reads
???? 286572? redo size
??????? 911? bytes sent via SQL*Net to client
?????? 1017? bytes received via SQL*Net from client
????????? 4? SQL*Net roundtrips to/from client
????????? 2? sorts (memory)
????????? 0? sorts (disk)
??????? 980? rows processed
SQL> rollback;
回退已完成。
SQL> insert into t select * from user_tables;
已創(chuàng)建980行。
統(tǒng)計(jì)信息
----------------------------------------------------------
????????? 0? recursive calls
??????? 144? db block gets
?????? 9027? consistent gets
????????? 0? physical reads
???? 267448? redo size
??????? 927? bytes sent via SQL*Net to client
?????? 1004? bytes received via SQL*Net from client
????????? 4? SQL*Net roundtrips to/from client
????????? 2? sorts (memory)
????????? 0? sorts (disk)
??????? 980? rows processed
?
Nologging模式下示例:
SQL> alter table t nologging;
表已更改。
SQL> insert into t select * from user_tables;
已創(chuàng)建980行。
統(tǒng)計(jì)信息
----------------------------------------------------------
??????? 239? recursive calls
??????? 132? db block gets
?????? 9061? consistent gets
????????? 0? physical reads
???? 262896? redo size
??????? 927? bytes sent via SQL*Net to client
?????? 1004? bytes received via SQL*Net from client
????????? 4? SQL*Net roundtrips to/from client
????????? 7? sorts (memory)
????????? 0? sorts (disk)
??????? 980? rows processed
SQL> rollback;
回退已完成。
SQL> insert /*+append */ into t select * from user_tables;
已創(chuàng)建980行。
統(tǒng)計(jì)信息
----------------------------------------------------------
????????? 8? recursive calls
???????? 40? db block gets
?????? 8938? consistent gets
????????? 0? physical reads
??????? 340? redo size? -- redo 減少很多
??????? 911? bytes sent via SQL*Net to client
?????? 1017? bytes received via SQL*Net from client
????????? 4? SQL*Net roundtrips to/from client
????????? 2? sorts (memory)
????????? 0? sorts (disk)
??????? 980? rows processed
?
這部分內(nèi)容也可參考Blog:
??????????????? Oracle DML NOLOGGING
http://blog.csdn.net/tianlesoftware/archive/2010/07/11/5701596.aspx
?
?
7.2 直接加載和索引
??????????????? 如果直接加載的表上有索引,Oracle不會(huì)像加載數(shù)據(jù)的方式那樣來處理索引的數(shù)據(jù),但是它同樣需要維護(hù)一個(gè)索引,這個(gè)成本很高,同時(shí)會(huì)生成很多的redo。
??????????????? 所以當(dāng)使用直接加載時(shí),通常是針對(duì)一些數(shù)據(jù)量非常大的表。如果這些表存在索引,將會(huì)帶來很大的性能影響,這時(shí)可以考慮先將索引disable或者drop掉,等加載數(shù)據(jù)后,之后在重新建立索引。
?
nologging示例:
?
SQL> insert /*+append */ into t select * from user_tables;
已創(chuàng)建980行。
?
統(tǒng)計(jì)信息
----------------------------------------------------------
????????? 0? recursive calls
???????? 40? db block gets
?????? 8936? consistent gets
????????? 0? physical reads
??????? 384? redo size
??????? 911? bytes sent via SQL*Net to client
?????? 1017? bytes received via SQL*Net from client
????????? 4? SQL*Net roundtrips to/from client
????????? 2? sorts (memory)
????????? 0? sorts (disk)
?????? ?980? rows processed
?
SQL> rollback;
回退已完成。
SQL> create index t_ind on t(table_name);
索引已創(chuàng)建。
SQL> insert /*+append */ into t select * from user_tables;
已創(chuàng)建980行。
?
統(tǒng)計(jì)信息
----------------------------------------------------------
???????? 40? recursive calls
??????? 170? db block gets
?????? 8955? consistent gets
????????? 4? physical reads
???? 149424? redo size
??????? 911? bytes sent via SQL*Net to client
?????? 1017? bytes received via SQL*Net from client
????????? 4? SQL*Net roundtrips to/from client
????????? 3? sorts (memory)
????????? 0? sorts (disk)
??????? 980? rows processed
SQL> rollback;
回退已完成。
SQL> insert? into t select * from user_tables;
已創(chuàng)建980行。
?
統(tǒng)計(jì)信息
----------------------------------------------------------
????????? 8? recursive calls
??????? 828? db block gets
?????? 9037? consistent gets
????????? 0? physical reads
???? 382832? redo size
??????? 927? bytes sent via SQL*Net to client
?????? 1005? bytes received via SQL*Net from client
????????? 4? SQL*Net roundtrips to/from client
????????? 2? sorts (memory)
????????? 0? sorts (disk)
??????? 980? rows processed
SQL> rollback;
回退已完成。
?
?
7.3 直接加載和并行
??????????????? 直接加載可以和并行執(zhí)行一同使用,這樣可以并行地向表中插入數(shù)據(jù)。 如:
???????????????
SQL>alter session enable parallel dml; ?-- 這里必須顯示的申明
SQL>insert /*+append parallel(t,2) */ into t select * from t1;
SQL>insert /*+append */ into t select * from t1;
?
注:在對(duì)insert 使用并行時(shí),Oracle自動(dòng)使用直接加載的方式進(jìn)行數(shù)據(jù)加載,所以在這種情況下append是可以省略的。
?
??????????????? 當(dāng)使用并行加載時(shí),Oracle 會(huì)按照并行度啟動(dòng)相應(yīng)數(shù)量的并行服務(wù)進(jìn)程,像串行執(zhí)行的直接加載的方式一樣,每個(gè)并行服務(wù)進(jìn)程都單獨(dú)分配額外的空間用于加載數(shù)據(jù),實(shí)際上Oracle 為每個(gè)并行服務(wù)進(jìn)程分配了一個(gè)臨時(shí)段,每個(gè)并行服務(wù)進(jìn)程將數(shù)據(jù)首先加載到各自的臨時(shí)段上,當(dāng)所有的并行進(jìn)程執(zhí)行完畢后,將各自的數(shù)據(jù)塊合并到一起,放到高水位之后,如果事務(wù)提交,則將高水位移到新加載的數(shù)據(jù)之后。
?
?
7.4 直接加載和SQL*LOADER
??????????????? 在SQL*LOADER中也可以使用直接加載,它比傳統(tǒng)方式效率更高,因?yàn)樗@開了SQL的解析和數(shù)據(jù)緩沖區(qū),直接將數(shù)據(jù)加載到數(shù)據(jù)文件,這對(duì)OLAP或者數(shù)據(jù)倉庫系統(tǒng)非常有用。
?
指定加載:
??????????????? Sqlldr userid=user/pwd control=control.ctl direct=true
?
指定并行和加載:
??????????????? Sqlldr userid=user/pwd control=control.ctl direct=true parallel=true
?
?
SQL*LOADER直接加載對(duì)索引的影響:
(1)索引為非約束性,直接加載可以在加載完畢后維護(hù)索引的完整性。
(2)索引為約束性索引,比如主鍵,直接加載仍然會(huì)將數(shù)據(jù)加載入庫,但是會(huì)將索引置為unusable.
?
?
如果使用SQL*LOADER的并行直接加載選項(xiàng),并且表上有索引,將導(dǎo)致加載失敗,這是我們可以在sqlloader中指定skip_index_maintenance=true, 來允許加載完成,但是索引狀態(tài)會(huì)變成unusable,需要手工rebuild.
?
關(guān)于SQL*LOADER的更多內(nèi)容,參考blog:
??????????????? Oracle SQL Loader
??????????????? http://blog.csdn.net/tianlesoftware/archive/2009/10/16/4674063.aspx
?
總結(jié)
以上是生活随笔為你收集整理的Oracle Parallel Execution(并行执行) .的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Oracle 绑定变量 详解 .
- 下一篇: alter system flush s