深入理解Oracle的并行操作
并行(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操作的處理速度一般非???#xff0c;不需要啟用并行。?
并行處理的機(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;
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------
Plan hash value: 3939201228
------------------------------------------------------------------------------------------------------------------
| Id? | Operation??????????????? | Name???? | Rows? | Bytes | Cost (%CPU)| Time???? |??? TQ? |IN-OUT| PQ Distrib |
------------------------------------------------------------------------------------------------------------------
|?? 0 | SELECT STATEMENT???????? |????????? |?? 107 |? 2782 |???? 3? (34)| 00:00:01 |??????? |????? |??????????? |
|?? 1 |? PX COORDINATOR????????? |????????? |?????? |?????? |??????????? |????????? |??????? |????? |??????????? |
|?? 2 |?? PX SEND QC (RANDOM)??? | :TQ10001 |?? 107 |? 2782 |???? 3? (34)| 00:00:01 |? Q1,01 | P->S | QC (RAND)? |
|?? 3 |??? HASH GROUP BY???????? |????????? |?? 107 |? 2782 |???? 3? (34)| 00:00:01 |? Q1,01 | PCWP |??????????? |
|?? 4 |???? PX RECEIVE?????????? |????????? |?? 107 |? 2782 |???? 3? (34)| 00:00:01 |? Q1,01 | PCWP |??????????? |
|?? 5 |????? PX SEND HASH??????? | :TQ10000 |?? 107 |? 2782 |???? 3? (34)| 00:00:01 |? Q1,00 | P->P | HASH?????? |
|?? 6 |?????? HASH GROUP BY????? |????????? |?? 107 |? 2782 |???? 3? (34)| 00:00:01 |? Q1,00 | PCWP |??????????? |
|?? 7 |??????? PX BLOCK ITERATOR |????????? |?? 107 |? 2782 |???? 2?? (0)| 00:00:01 |? Q1,00 | PCWC |??????????? |
|?? 8 |???????? TABLE ACCESS FULL| EMP2???? |?? 107 |? 2782 |???? 2?? (0)| 00:00:01 |? Q1,00 | PCWP |??????????? |
------------------------------------------------------------------------------------------------------------------
Note
-----
?? - dynamic sampling used for this statement
19 rows selected.?
通過執(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ù),按照隨機(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è)串行操作
Parallel to Parallel(P->P):表示一個(gè)并行操作向另一個(gè)并行操作發(fā)送數(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ì)遇到如下等待事件?
PX Deq Credit: send blkd?
這是一個(gè)有并行環(huán)境的數(shù)據(jù)庫中,從statspack 或者AWR中經(jīng)常可以看到的等待事件。 在Oracle 9i 里面, 這個(gè)等待時(shí)間被列入空閑等待。?
一般來說空閑等待可以忽略它,但是實(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í)間很長(zhǎng)時(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í)行的使用范圍?
Parallel Query( 并行查詢 )
并行查詢可以在查詢語句,子查詢語句中使用,但是不可以使用在一個(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;?
Parallel DDL(并行DDL操作,如建表,建索引等)?
表的并行操作
CREATE TABLE table_name parallel 4 AS SELECT?....
ALTER TABLE table_name move partition?partition_name parallel 4;
Alter table table_name split partition?partition_name ...... parallel 4;?
Alter table?table_name?coalesce partition?parallel 4;?
DDL操作,我們可以通過trace 文件來查看它的執(zhí)行過程。?
alter session set events '10046 trace name context forever,level 12';?
alter session set events '10046 trace name context off' ;?
創(chuàng)建索引的并行執(zhí)行?
創(chuàng)建索引時(shí)使用并行方式在系統(tǒng)資源充足的時(shí)候會(huì)使性能得到很大的提高,特別是在OLAP系統(tǒng)上對(duì)一些很大的表創(chuàng)建索引時(shí)更是如此。 以下的創(chuàng)建和更改索引的操作都可以使用并行:?
Create index?index_name on table_name(colum_name) parallel 4;
Alter index index_name rebuild?parallel 4
Alter index?index_name?rebuild partition?partition_name parallel 4;
Alter index?index_name?split partition?partition_name .... parallel 4;?
注意:索引上的并行度只有在訪問索引的時(shí)候才可以被使用。?
總結(jié):?
使用并行方式,不論是創(chuàng)建表,修改表,創(chuàng)建索引,重建索引,他們的機(jī)制都是一樣的,那就是Oracle 給每個(gè)并行服務(wù)進(jìn)程分配一塊空間,每個(gè)進(jìn)程在自己的空間里處理數(shù)據(jù),最后將處理完畢的數(shù)據(jù)匯總,完成SQL的操作。?
Parallel DML(并行DML操作,如insert,update,delete等)?
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ì)忽略它。?
delete,update和merge樣例如下?
delete /*+ parallel(table_name 4) */ from test;
update/*+ parallel(table_name 4) */ test set id=100;
merge /*+ parallel(table_name 4) */ into table_name ...
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ū)表來說是沒有意義的。 分區(qū)表的并行屬性只能在表級(jí)別設(shè)置,不能在分區(qū)級(jí)別設(shè)置。
注:經(jīng)筆者測(cè)試中非分區(qū)表下,?Delete,update,merge也可以執(zhí)行并行操作,不知道是版本原因還是其他原因,待考證?
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è)并行。 也有如下語法
Insert into t select /*+parallel(t1 2) */ * from t1;?
Insert /*+parallel(t 2) */ into t select? * from t1;?
并行執(zhí)行的設(shè)定?
并行相關(guān)的初始話參數(shù)?
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ù)量。?
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è)定值。默認(rèn)值為PARALLEL_THREADS_PER_CPU * CPU_COUNT * concurrent_parallel_users * 5
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í)行性能。
PARALLEL_DEGREE_POLICY
PARALLEL_DEGREE_POLICY specifies whether or not automatic degree of Parallelism, statement queuing, and in-memory parallel execution will be enabled.Values:
MANUAL:?Disables automatic degree of parallelism, statement queuing, and in-memory parallel execution. This reverts the behavior of parallel execution to what it was prior to Oracle Database 11g Release 2 (11.2). This is the default.
LIMITED:?Enables automatic degree of parallelism for some statements but statement queuing and in-memory Parallel Execution are disabled. Automatic degree of parallelism is only applied to those statements that access tables or indexes decorated explicitly with the DEFAULT degree of parallelism using the PARALLEL clause. Statements that do not access any tables or indexes decorated with the DEFAULT degree of parallelism will retain the MANUAL behavior.
AUTO: Enables automatic degree of parallelism, statement queuing, and in-memory parallel execution.
Note: If the table parallel degree has been set as "default",? sql would compute its own DOP regardless parallel_degree_policy is MANUAL or LIMITED. When parallel_degree_policy=AUTO, it would trigger automatically parallel degree?.
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)程。
Note:當(dāng)parallel_degree_policy=AUTO時(shí),如果沒有獲得申請(qǐng)的進(jìn)程,則該并行sql則會(huì)進(jìn)入隊(duì)列
PARALLEL_FORCE_LOCAL
This parameter specifies whether a SQL statement executed in parallel is restricted to a single instance in an Oracle RAC environment. By setting this parameter to TRUE, you restrict the scope of the parallel server processed to the single Oracle RAC instance where the query coordinator is running.
The recommended value for the PARALLEL_FORCE_LOCAL parameter is FALSE.
PARALLEL_DEGREE_POLICY
該參數(shù)為11g的新增參數(shù),有如下3個(gè)屬性值:
manual,默認(rèn)值,表示不自動(dòng)調(diào)節(jié)并行度。
auto,自動(dòng)調(diào)節(jié)并行度。
limited,對(duì)于在相關(guān)表或者索引上已經(jīng)定義了并行度的查詢進(jìn)行自動(dòng)并行度調(diào)節(jié),沒有在相關(guān)表或者索引上已經(jīng)定義并行度的查詢不進(jìn)行自動(dòng)并行度調(diào)節(jié)。
PARALLEL_THREADS_PER_ CPU
一個(gè)CPU 在并行執(zhí)行過程中可處理的進(jìn)程或線程的數(shù)量,并優(yōu)化并行自適應(yīng)算法和負(fù)載均衡算法。如果計(jì)算機(jī)在執(zhí)行一個(gè)典型查詢時(shí)有超負(fù)荷的跡象,應(yīng)減小該數(shù)值為任何非零值。 根據(jù)操作系統(tǒng)而定 (通常為 2)
parallel_automatic_tuning
如果設(shè)置為 TRUE,Oracle 將為控制并行執(zhí)行的參數(shù)確定默認(rèn)值。除了設(shè)置該參數(shù)外,你還必須為系統(tǒng)中的表設(shè)置并行性。以在10g中廢棄,只為向下兼容保留。
PARALLEL_MIN_TIME_THRESHOLD
This parameter specifies the minimum execution time a statement should have before the statement is considered for automatic degree of parallelism. By default, this is set to 10 seconds. Automatic degree of parallelism is only enabled if PARALLEL_DEGREE_POLICY is set to AUTO or LIMITED. The syntax is:
PARALLEL_MIN_TIME_THRESHOLD = { AUTO | integer }
The default is AUTO.
PARALLEL_SERVERS_TARGET
This parameter specifies the number of parallel server processes allowed to run parallel statements before statement queuing is used. The default value is:
PARALLEL_THREADS_PER_CPU * CPU_COUNT * concurrent_parallel_users * 2
In the formula, the value assigned to concurrent_parallel_users running at the default degree of parallelism on an instance is dependent on the memory management setting. If automatic memory management is disabled (manual mode), then the value of concurrent_parallel_users is 1. If PGA automatic memory management is enabled, then the value of concurrent_parallel_users is 2. If global memory management or SGA memory target is used in addition to PGA automatic memory management, then the value of concurrent_parallel_users is 4.
When PARALLEL_DEGREE_POLICY is set to AUTO, statements that require parallel execution are queued if the number of parallel processes currently in use on the system equals or is greater than PARALLEL_SERVERS_TARGET. This is not the maximum number of parallel server processes allowed on a system (that is controlled by PARALLEL_MAX_SERVERS). However, PARALLEL_SERVERS_TARGET and parallel statement queuing is used to ensure that each statement that requires parallel execution is allocated the necessary parallel server resources and the system is not flooded with too many parallel server processes.
parallel_execution_message_size
指定并行執(zhí)行 (并行查詢、PDML、并行恢復(fù)和復(fù)制) 消息的大小。如果值大于 2048 或 4096,就需要更大的共享池。如果 PARALLEL_AUTOMATIC_TUNING =TRUE,將在大存儲(chǔ)池之外指定消息緩沖區(qū)。 如果PARALLEL_AUTOMATIC_TUNING 為 FALSE,通常值為 2148;如果PARALLEL_AUTOMATIC_TUNING 為 TRUE ,則值為 4096 (根據(jù)操作系統(tǒng)而定)。
PARALLEL_DEGREE_LIMIT
With automatic degree of parallelism, Oracle automatically decides whether or not a statement should execute in parallel and what degree of parallelism the statement should use. The optimizer automatically determines the degree of parallelism for a statement based on the resource requirements of the statement. However, the optimizer will limit the degree of parallelism used to ensure parallel server processes do not flood the system. This limit is enforced by PARALLEL_DEGREE_LIMIT
Values:
CPU: The maximum degree of parallelism is limited by the number of CPUs in the system. The formula used to calculate the limit is PARALLEL_THREADS_PER_CPU * CPU_COUNT * the number of instances available (by default, all the opened instances on the cluster but can be constrained using PARALLEL_INSTANCE_GROUP or service specification). This is the default.
IO:?The maximum degree of parallelism the optimizer can use is limited by the I/O capacity of the system. The value is calculated by dividing the total system throughput by the maximum I/O bandwidth per process. You must run the DBMS_RESOURCE_MANAGER.CALIBRATE_IO procedure on the system in order to use the IO setting. This procedure will calculate the total system throughput and the maximum I/O bandwidth per process.
integer:?A numeric value for this parameter specifies the maximum degree of parallelism the optimizer can choose for a SQL statement when automatic degree of parallelism is active. Automatic degree of parallelism is only enabled if PARALLEL_DEGREE_POLICY is set to AUTO or LIMITED.
并行度可以通過以下三種方式來設(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;?
SQL>alter session force parallel query;?
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ì)使性能大幅下降。?
如何啟用并行
可以用hint、alter session或者設(shè)置對(duì)象并行屬性三種方式設(shè)置啟用并行。三種方式任意一種就可以使并行生效,如果多種方式同時(shí)存在的話,則優(yōu)先級(jí)順序是:hint -> alter session -> table/index degree。
alter session force query parallel 8;
?
alter session enable parallel dml;
alter session force parallel dml parallel 8;
alter session force parallel ddl parallel 8;
注意:上述的alter session enable只是表示讓當(dāng)前會(huì)話支持并行,最終并行需要通過hint或者table/index degree來實(shí)現(xiàn);而alter session force表示強(qiáng)制并行,無需hint等配合使用。
11g中的并行?
在Oracle 11g R2以及之前的版本,你的SQL執(zhí)行可能被延遲,直到有充足的并行服務(wù)器可用。
Oracle有一種輪換IO機(jī)制,叫做“直接路徑IO”,如果它判斷到繞過緩存區(qū)直接執(zhí)行IO會(huì)更快速的話, 它就會(huì)啟用。例如,Oracle在讀寫臨時(shí)段進(jìn)行排序或者整理中間結(jié)果集時(shí)就會(huì)使用直接IO。從Oracle 11g開始,Oracle有時(shí)也優(yōu)先利用直接路徑IO來處理串行表訪問,而不是正常的緩存IO。
在執(zhí)行并行查詢操作時(shí),Oracle通常會(huì)使用直接路徑IO。通過使用直接路徑IO,Oracle可以避免創(chuàng)建高速緩存競(jìng)爭(zhēng),并可以使IO更加優(yōu)化地在并行進(jìn)程之間分配。此外,對(duì)于執(zhí)行全表掃描的并行操作,在高速緩存找到匹配數(shù)據(jù)的機(jī)會(huì)相當(dāng)?shù)?#xff0c;因此高速緩存幾乎沒有增加什么價(jià)值。
在Oracle 10g以及更早的版本,并行查詢總是使用直接路徑IO,而串行查詢將總是使用緩存IO。在11g中,Oracle可以對(duì)并行查詢利用緩存IO(從11g R2以后的版本支持),而且串行查詢也可能利用直接路徑IO。然而,并行查詢?nèi)匀徊惶赡芾镁彺鍵O,因此,可能比串行查詢需要更高的IO成本。當(dāng)然, 更高的IO成本將在所有并行進(jìn)程之間共享,這樣整體性能仍可能更勝一籌。
并行的優(yōu)化準(zhǔn)則?
從優(yōu)化串行執(zhí)行的SQL開始?
一個(gè)最理想的并行計(jì)劃與最佳的串行計(jì)劃可能是有區(qū)別的。例如,并行處理通常從表或索引的掃描開始,而最佳串行計(jì)劃可能是基于索引查找開始。然而,你應(yīng)該確保你的查詢?cè)谶M(jìn)行并行優(yōu)化之前先對(duì)串行執(zhí)行進(jìn)行優(yōu)化,原因如下:
1、串行調(diào)試的結(jié)構(gòu)和方法主要針對(duì)索引和統(tǒng)計(jì)集合,而這些經(jīng)常對(duì)好的并行調(diào)試也非常關(guān)鍵。
2、如果請(qǐng)求并行執(zhí)行的資源不可用,你的查詢可能被串行化(這取決于“PARALLEL_DEGREE_ POLICY”和“PARALLEL_MIN_PERCENT”的設(shè)置)。在這種情況下,你要確保你并行查詢的串行計(jì)劃足夠好。
缺少調(diào)優(yōu)的SQL甚至可能變成更差的SQL,至少考慮到對(duì)其他用戶的影響時(shí)是這樣,這使它被允許消耗數(shù)據(jù)庫服務(wù)器更多的CPU和IO資源。
在為并行執(zhí)行優(yōu)化SQL語句時(shí),要從未串行執(zhí)行SQL優(yōu)化開始。
確保該SQL是合適的并行執(zhí)行SQL?
不是每個(gè)SQL都能從并行執(zhí)行中獲益的。下面是一些例子,這些情況的SQL語句可能不應(yīng)該被并行化。
1、串行執(zhí)行時(shí),執(zhí)行時(shí)間很短的SQL語句。
2、可能在多個(gè)會(huì)話中高并發(fā)率運(yùn)行的SQL語句。
3、基于索引查找的SQL語句。非并行的索引查找或者范圍掃描不能被并行化。然而,索引全掃描可以被并行化。在分區(qū)索引上的索引查找也可以被并行化。
綜上3點(diǎn),OLTP類型的查詢通常不適合并行化處理。
確保系統(tǒng)適合配置為并行執(zhí)行?
不是所有的SQL都適合并行執(zhí)行,也不是所有的數(shù)據(jù)庫服務(wù)器主機(jī)適合配置并行處理。在當(dāng)今世界,大部分物理服務(wù)器主機(jī)都滿足如下最小需求:多塊CPU和 跨多個(gè)物理驅(qū)動(dòng)器的數(shù)據(jù)帶。然而,一些虛擬主機(jī)可能不滿足這些最小需求,而桌面計(jì)算機(jī)通常只有唯一的磁盤設(shè)備,因此通常不適合調(diào)整為并行執(zhí)行。
不要嘗試在那些不滿足最小需求(多塊CPU和跨多個(gè)磁盤驅(qū)動(dòng)器的數(shù)據(jù)帶)的計(jì)算機(jī)系統(tǒng)上使用并行執(zhí)行。
確保執(zhí)行計(jì)劃的所有部分都被并行化了?
在復(fù)雜的并行SQL語句中,很重要的一點(diǎn)是要確保該查詢執(zhí)行的所有重要步驟都實(shí)現(xiàn)了并行。如果某復(fù)雜查詢的其中一個(gè)步驟是串行執(zhí)行的,其他并行步驟可能 也不得不等待該串行步驟完成,這樣并行機(jī)制的優(yōu)勢(shì)就完全喪失了?!癙LAN_TABLE”表中的“OTHER_TAG”列用 “PARALLEL_FROM_SERIAL”標(biāo)記指定了這樣一個(gè)步驟,“DBMS_XPLAN”在“IN-OUT”列中記錄了“S->P”。例如:在下面的例子中表“T1”是并行化的,但是表“T”不是。對(duì)兩個(gè)表的連接和“GROUP BY”包括許多并行操作,但是對(duì)“T”表的全表掃描不是并行化的,串到并(S->P)標(biāo)記展示了“t”行被串行提取到后續(xù)并行操作中:
SQL> ALTER TABLE customers PARALLEL(DEGREE 4);
SQL> ALTER TABLE sales NOPARALLEL ;
SQL> explain plan for select /*+ ordered use_hash(t1) */ t.name,sum(t.id) from t,t1 where t.id=t1.object_id group by t.name;
SQL> ? 1* select * from table(dbms_xplan.display)
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2575143521
----------------------------------------------------------------------------------------------------------------------
| Id? | Operation??????????????????? | Name???? | Rows? | Bytes | Cost (%CPU)| Time???? |??? TQ? |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------
|?? 0 | SELECT STATEMENT???????????? |????????? |??? 61 |? 4758 |??? 22? (10)| 00:00:01 |??????? |????? |??????????? |
|?? 1 |? PX COORDINATOR????????????? |????????? |?????? |?????? |??????????? |????????? |??????? |????? |??????????? |
|?? 2 |?? PX SEND QC (RANDOM)??????? | :TQ10002 |??? 61 |? 4758 |??? 22? (10)| 00:00:01 |? Q1,02 | P->S | QC (RAND)? |
|?? 3 |??? HASH GROUP BY???????????? |????????? |??? 61 |? 4758 |??? 22? (10)| 00:00:01 |? Q1,02 | PCWP |??????????? |
|?? 4 |???? PX RECEIVE?????????????? |????????? |??? 61 |? 4758 |??? 22? (10)| 00:00:01 |? Q1,02 | PCWP |??????????? |
|?? 5 |????? PX SEND HASH??????????? | :TQ10001 |??? 61 |? 4758 |??? 22? (10)| 00:00:01 |? Q1,01 | P->P | HASH?????? |
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|?? 6 |?????? HASH GROUP BY????????? |????????? |??? 61 |? 4758 |??? 22? (10)| 00:00:01 |? Q1,01 | PCWP |??????????? |
|*? 7 |??????? HASH JOIN???????????? |????????? |??? 61 |? 4758 |??? 21?? (5)| 00:00:01 |? Q1,01 | PCWP |??????????? |
|?? 8 |???????? BUFFER SORT????????? |????????? |?????? |?????? |??????????? |????????? |? Q1,01 | PCWC |??????????? |
|?? 9 |????????? PX RECEIVE????????? |????????? |??? 61 |? 3965 |??? 12?? (0)| 00:00:01 |? Q1,01 | PCWP |??????????? |
|? 10 |?????????? PX SEND BROADCAST? | :TQ10000 |??? 61 |? 3965 |??? 12?? (0)| 00:00:01 |??????? | S->P | BROADCAST? |
|? 11 |??????????? TABLE ACCESS FULL | T??????? |??? 61 |? 3965 |??? 12?? (0)| 00:00:01 |??????? |????? |??????????? |
|? 12 |???????? PX BLOCK ITERATOR??? |????????? | 52078 |?? 661K|???? 8?? (0)| 00:00:01 |? Q1,01 | PCWC |??????????? |
|? 13 |????????? INDEX FAST FULL SCAN| T1_IDX?? | 52078 |?? 661K|???? 8?? (0)| 00:00:01 |? Q1,01 | PCWP |??????????? |
----------------------------------------------------------------------------------------------------------------------
像前面這種情況,部分并行化執(zhí)行計(jì)劃可能會(huì)導(dǎo)致兩方面效果都很差:消耗的時(shí)間并沒有改善,因?yàn)榇胁僮餍纬闪苏麄€(gè)執(zhí)行的瓶頸。然而,該SQL還捆綁了并行服務(wù)器進(jìn)程,而且可能影響其他并發(fā)執(zhí)行SQL的性能。
如果我們?yōu)楸怼皌”設(shè)置一個(gè)默認(rèn)的并行度,該串行瓶頸將會(huì)消失。對(duì)“t”表的全掃描現(xiàn)在是按并行執(zhí)行了,而且“串到并S->P”瓶頸將被全并行的“并到并P->P”操作替代
在優(yōu)化并行執(zhí)行計(jì)劃時(shí),要確保所有相關(guān)步驟都在并行執(zhí)行:“DBMS_XPLAN”中的串到并S->P 標(biāo)記或者“PLAN_TABLE”中的“PARALLEL_FROM_SERIAL”通常指示在并行計(jì)劃的某些方面存在串行瓶頸。
Monitor parallel execution
SQL> select * from v$pq_sesstat;
STATISTIC????????????????????? LAST_QUERY SESSION_TOTAL
------------------------------ ---------- -------------
Queries Parallelized??????????????????? 1??????????? 13
DML Parallelized??????????????????????? 0???????????? 0
DDL Parallelized??????????????????????? 0???????????? 0
DFO Trees?????????????????????????????? 1??????????? 13
Server Threads????????????????????????? 6???????????? 0
Allocation Height?????????????????????? 3???????????? 0
Allocation Width??????????????????????? 1???????????? 0
Local Msgs Sent?????????????????????? 362??????? 303740
Distr Msgs Sent???????????????????????? 0???????????? 0
Local Msgs Recv'd???????????????????? 368??????? 303782
Distr Msgs Recv'd?????????????????????? 0???????????? 0
11 rows selected.
SQL> select? DFO_NUMBER, TQ_ID, SERVER_TYPE,? NUM_ROWS ,BYTES,process from v$pq_tqstat order by dfo_number , tq_id , server_type;
DFO_NUMBER????? TQ_ID SERVER_TYPE?????? NUM_ROWS????? BYTES PROCESS
---------- ---------- --------------- ---------- ---------- --------
???????? 1????????? 0 Consumer???????????? 17151???? 100454 P001
???????? 1????????? 0 Consumer???????????? 17242???? 100969 P002
???????? 1????????? 0 Consumer???????????? 17257???? 101058 P000
???????? 1????????? 0 Producer????????????? 1971?????? 9955 P004
???????? 1????????? 0 Producer???????????? 29565???? 174989 P005
???????? 1????????? 0 Producer???????????? 20114???? 117537 P003
???????? 1????????? 1 Consumer?????????????? 893?????? 8107 P002
???????? 1????????? 1 Consumer????????????? 2914????? 26341 P001
???????? 1????????? 1 Consumer???????????????? 0???????? 60 P000
???????? 1????????? 1 Producer?????????????? 611?????? 5494 P003
???????? 1????????? 1 Producer????????????? 2593????? 23493 P005
???????? 1????????? 1 Producer?????????????? 603?????? 5521 P004
???????? 1????????? 2 Consumer????????????? 3807????? 19040 QC
???????? 1????????? 2 Producer????????????? 2914????? 14545 P001
???????? 1????????? 2 Producer?????????????? 893?????? 4475 P002
???????? 1????????? 2 Producer???????????????? 0???????? 20 P000
16 rows selected.
Obviously, from the v$pq_tqstat, the DOP is downgrade to 3, and have two slave sets.? From the v$tq_sesstat, we can see that what’s the process. How these processes cooperated together to generated the result. In this sample, P003, P004,P005 generate the data and feed to P000,P001,P002, totally twice. Then P000,P001,P002 feed the data to QC, the query coordinator. Also, we can find that P000 at the first time received 17257 rows, but at the second time it received 0 rows, and lastly, it product 0 rows to QC. Why?
Let’s look at the execution plan for further investigation.
SQL> @utlxplp
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1177066807
-----------------------------------------------------------------------------------------------------------------
| Id? | Operation?????????????? | Name???? | Rows? | Bytes | Cost (%CPU)| Time???? |??? TQ? |IN-OUT| PQ Distrib |
-----------------------------------------------------------------------------------------------------------------
|?? 0 | SELECT STATEMENT??????? |????????? |? 3867 |?? 147K|??? 13?? (8)| 00:00:01 |??????? |????? |??????????? |
|?? 1 |? PX COORDINATOR???????? |????????? |?????? |?????? |??????????? |????????? |??????? |????? |??????????? |
|?? 2 |?? PX SEND QC (RANDOM)?? | :TQ10002 |? 3867 |?? 147K|??? 13?? (8)| 00:00:01 |? Q1,02 | P->S | QC (RAND)? |
|*? 3 |??? HASH JOIN BUFFERED?? |????????? |? 3867 |?? 147K|??? 13?? (8)| 00:00:01 |? Q1,02 | PCWP |??????????? |
|?? 4 |???? PX RECEIVE????????? |????????? | 53332 |?? 677K|???? 7?? (0)| 00:00:01 |? Q1,02 | PCWP |??????????? |
|?? 5 |????? PX SEND HASH?????? | :TQ10000 | 53332 |?? 677K|???? 7?? (0)| 00:00:01 |? Q1,00 | P->P | HASH?????? |
|?? 6 |?????? PX BLOCK ITERATOR |????????? | 53332 |?? 677K|???? 7?? (0)| 00:00:01 |? Q1,00 | PCWC |??????????? |
|?? 7 |??????? TABLE ACCESS FULL| PRODUCTS | 53332 |?? 677K|???? 7?? (0)| 00:00:01 |? Q1,00 | PCWP |??????????? |
|?? 8 |???? PX RECEIVE????????? |????????? |? 3867 |??? 98K|???? 5?? (0)| 00:00:01 |? Q1,02 | PCWP |??????????? |
|?? 9 |????? PX SEND HASH?????? | :TQ10001 |? 3867 |??? 98K|???? 5?? (0)| 00:00:01 |? Q1,01 | P->P | HASH?????? |
|? 10 |?????? PX BLOCK ITERATOR |????????? |? 3867 |??? 98K|???? 5?? (0)| 00:00:01 |? Q1,01 | PCWC |??????????? |
|? 11 |??????? TABLE ACCESS FULL| COSTS??? |? 3867 |??? 98K|???? 5?? (0)| 00:00:01 |? Q1,01 | PCWP |??????????? |
-----------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
?? 3 - access("C"."PROD_ID"="P"."PROD_ID")
This is a hash-hash parallel distribute, using hash joining. firstly, Slave set(Q1,00) scan products table and send the results to slave set(Q1,02), and slave set(Q1,01) scan the costs table and send results to slave set(Q1,02), which slave in slave set(Q1,02) to send to is dependent on the hash value of join key. as the table costs only have two distinct values for prod_id, so the rows in costs only have two target slave to send to, resulting one slave of the slave set (Q1,02) receive 0 rows. After the slaves in (Q1,02) received? rows from the other two slave sets, they hash join the rows and send the result to QC, obviously, one slave will have no rows to process.
This is why 0 rows in the above output.
Also, you can enable the trace for parallel execution, through this way:
alter session set events '10132 trace name context forever';
Compute the variance of bytes grouped by TQ_ID. Large variances indicate workload imbalances. You should investigate large variances to determine whether the producers start out with unequal distributions of data, or whether the distribution itself is skewed. If the data itself is skewed, this might indicate a low cardinality, or low number of distinct values.
Some Common Sense
One of my favourite descriptions of performance tuning, althou gh I can’t remember where I first heard it, is that it is based on ‘informed common sense’. That really captures my ow n experiences of performance tu ning. Yes, you need to use proper analysis techniques and often a great deal of technical knowledge, but that’s all devalued if you’re completely missing the point . So let’s take a step away from the technical and consider the big picture.
Don’t even think about implementing Parallel Execution un less you are prepared to invest some time in initial testing, followed by ongoing performance monitoring. If you don’t, you might one day hit performance problems either server-wide or on an individual user session that you’d never believe (until it happens to you).
Parallel Execution is designed to utilise hardware as heavily as possible. If you are running on a single-CPU server with two hard disk drives and 512Mb RAM, don’t expect significant perfor mance improvements just because you switch PX on. The more CPUs , disk drives, controllers and RAM you have installed on your server, the better the results are going to be.
Although you may be able to use Parallel Execution to make an inefficient SQL stat ement run many times faster, that would be incredibly stupid. It’s essential that you tune the SQL first . In the end, doing more work than you should be, but more quickly, is still doing more work than you should be! To put it another way, don’t use PX as a dressing for a poorly designed application. Reduce the wo rkload to the minimum needed to achieve the task and then start using the server facilities to make it run as quickly as possible. Seems obvious, doesn’t it?
If you try to use PX to benefit a large number of user s performing online queries yo u may eventually bring the server to its knees. Well, maybe not if you use th e Adaptive Multi-User algorithm, but then it’s essential that both you and, more important, your users unders tand that response time is going to be very variable when the machine gets busy.
Using PX for a query that runs in a few seconds is pointless. You’re just going to use more resources on the server for very little improvemen t in the run time of the query. It might well run more slowly!
Sometimes when faced with a slow i/o subsystem you migh t find that higher degrees of parallelism are useful because the CPUs are spending more ti me waiting for i/o to complete. Ther efore they are more likely to be available for another PX slave (that isn’t waiting on i/o) to use. This was certainly my experience at one site. However, it’s also true that using PX will usually lead to a busier i/o subsystem because the server is likely to favour full scans over indexed retrieva l. There are no easy answers here - you really need to carry out some analysis of overall system resource usage to identify where the bottlenecks are an d adjust the configuration accordingly.
Consider whether PX is the correct parallel solution for overnight batch operations. It may be that you can achieve better performance using multip le streams of jobs, each single-threa ded, or maybe you would be better with one stream of jobs which uses PX. It depends on your application so the only sure way to find out is to try the different approaches .
BTW, introduce two useful link about parallel execution.
Oracle Database Parallel Execution Fundamental
http://www.oracle.com/technetwork/articles/datawarehouse/twp-parallel-execution-fundamentals-133639.pdf
How Parallel Execution Works
http://docs.oracle.com/cd/E11882_01/server.112/e25523/parallel002.htm#VLDBG0101
?
參考至:《讓Oracle跑得更快》譚懷遠(yuǎn)著
?????????? 《讓Oracle跑得更快2》譚懷遠(yuǎn)著?
?????????? http://howe.im/%E6%95%B0%E6%8D%AE%E5%BA%93/137.html
?????????? http://www.cnblogs.com/daduxiong/archive/2010/08/24/1807427.html
?????????? http://www.searchdatabase.com.cn/showcontent_44070.htm
?????????? http://xuguohao.gotoip55.com/?p=142
?????????? http://blog.csdn.net/tianlesoftware/article/details/5854583
?????????? http://docs.oracle.com/cd/E11882_01/server.112/e17110/initparams176.htm
?????????? http://space.itpub.net/17203031/viewspace-696389
???????????http://os2ora.com/monitor-parallel-execution/
???????????http://oracledoug.com/px.pdf
???????????http://docs.oracle.com/cd/E11882_01/server.112/e25523/parallel006.htm#VLDBG1513
???????????http://www.oracle.com/technetwork/articles/datawarehouse/twp-parallel-execution-fundamentals-133639.pdf
???????????http://docs.oracle.com/cd/E11882_01/server.112/e25523/parallel005.htm#CIHHGECI
???????????http://docs.oracle.com/cd/E11882_01/server.112/e40402/initparams181.htm#REFRN10310
???????????http://www.cnblogs.com/luoyx/archive/2011/12/26/2302587.html
文章轉(zhuǎn)自:http://czmmiao.iteye.com/blog/1487568
轉(zhuǎn)載于:https://blog.51cto.com/wilsonking/1636404
總結(jié)
以上是生活随笔為你收集整理的深入理解Oracle的并行操作的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 开源的DevOps开发工具箱
- 下一篇: 配置IntelliJ IDEA