所謂並行執行,是指可以將一個大型串行任務(任何DML,或者通常的DDL)物理地劃分爲多個較小的部分,這些較小的部分能夠同時獲得處理。算法
並行執行本質上是一個不可擴縮的解決方案,設計爲容許單個用戶或每一個特定SQL語句佔用數據庫的全部資源。若是某個特性容許一我的使用全部可用的資源,假若再容許兩我的使用這個特性,就會遇到明顯的競爭問題。數據庫
在應用並行執行以前,須要保證如下兩點成立:
必須有一個很是大的任務,如對50GB數據進行全面掃描。
必須有足夠的可用資源。在並行全面掃描50GB數據以前,你要確保有足夠的空閒CPU(以容納並行進程),還要有足夠的I/O通道,等等。服務器
scott@ORCL>explain plan for 2 select count(status) from big_table; 已解釋。 scott@ORCL>select * from table(dbms_xplan.display); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------------------------------------- Plan hash value: 599409829 -------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 7 | 47422 (1)| 00:09:30 | | 1 | SORT AGGREGATE | | 1 | 7 | | | | 2 | TABLE ACCESS FULL| BIG_TABLE | 11M| 76M| 47422 (1)| 00:09:30 | -------------------------------------------------------------------------------- 已選擇9行。
這是一個典型的串行計劃。這裏不涉及並行化,由於咱們沒有請求啓用並行查詢,而默認狀況下並不啓用並行查詢。併發
啓用並行查詢有多種方法,能夠直接在查詢中使用一個提示,或者修改表,要求考慮並行執行路徑。分佈式
能夠具體指定這個表的執行路徑中要考慮的並行度。例如,能夠告訴Oracle:「咱們但願你在建立這個表的執行計劃時使用並行度4」:ide
scott@ORCL>alter table big_table parallel 4; 表已更改。
但我更喜歡這樣告訴Oracle:「請 考慮並行執行,可是你要根據當前的系統工做負載和查詢自己來肯定適當的並行度」。也就是說,並行度要隨着系統上工做負載的增減而變化。若是有充足的空閒資 源,並行度會上升;若是可用資源有限,並行度則會降低。這樣就不會爲機器強加一個固定的並行度。利用這種方法,容許Oracle動態地增長或減小查詢所需的併發資源量。
所以,咱們只是經過如下ALTER TABLE命令來啓用對這個表的並行查詢:工具
scott@ORCL>alter table big_table parallel; 表已更改。
僅此而已。如今,對這個表的操做就會考慮並行查詢。從新運行解釋計劃,可能看到如下結果:spa
scott@ORCL>explain plan for 2 select count(status) from big_table; 已解釋。 scott@ORCL>select * from table(dbms_xplan.display); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------------------------------------- Plan hash value: 2894119656 -------------------------------------------------------------------------------- --------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib | -------------------------------------------------------------------------------- --------------------------------- | 0 | SELECT STATEMENT | | 1 | 7 | 6574 (1)| 00:01: 19 | | | | | 1 | SORT AGGREGATE | | 1 | 7 | | | | | | | 2 | PX COORDINATOR | | | | | | | | | | 3 | PX SEND QC (RANDOM) | :TQ10000 | 1 | 7 | | | Q1,00 | P->S | QC (RAND) | | 4 | SORT AGGREGATE | | 1 | 7 | | | Q1,00 | PCWP | | | 5 | PX BLOCK ITERATOR | | 11M| 76M| 6574 (1)| 00:01: 19 | Q1,00 | PCWC | | | 6 | TABLE ACCESS FULL| BIG_TABLE | 11M| 76M| 6574 (1)| 00:01: 19 | Q1,00 | PCWP | | -------------------------------------------------------------------------------- --------------------------------- 已選擇13行。
並行查詢就是這樣工做的,它要求一系列並行執行服務器同心合力地工做,生成子結果,這些子結果能夠傳送給其餘並行執行服務器作進一步的處理,也能夠傳送給並行查詢的協調器。設計
在這個特定的例子中,BIG_TABLE分佈在一個表空間的4個不一樣的設備上(這個表空間有4個數據文件)。實現並行執行時,一般「最好」將數據儘量地分佈在多個物理設備上。能夠經過多種途徑作到這一點:code
跨磁盤使用RAID條紋(RAID striping);
使用ASM(利用其內置條紋);
使用分區將BIG_TABLE物理地隔離到多個磁盤上;
使用一個表空間中的多個數據文件,第二容許Oracle在多個文件中爲BIG_TABLE段分配區段。
咱們能夠觀察到爲並行執行服務器建立的各個獨立事務。
因爲PDML採用的一種僞分佈式的實現,所以存在一些限制:
PDML操做期間不支持觸發器。由於觸發器可能會向更新增長大量開銷。
PDML期間,不支持某些聲明方式的引用完整性約束,由於表中的每一片(部分)會在單獨的會話中做爲單獨的事務進行修改。
在提交或回滾以前,不能訪問用PDML修改的表。
PDML不支持高級複製(由於複製特性的實現要基於觸發器)。
不支持延遲約束(也就是說,採用延遲模式的約束)。
若是表是分區的,PDML只可能在有位圖索引或LOB列的表上執行,並且並行度取決於分區數。在這種狀況下,沒法在分區內並行執行一個操做,由於每一個分區只有一個並行執行服務器來處理。
執行PDML時不支持分佈式事務。
PDML不支持聚簇表。
如下SQL DDL命令容許」並行化「:
CREATE INDEX:多個並行執行服務器能夠掃描表、對數據排序,並把有序的段寫出到索引結構。
CREATE TABLE AS SELECT:執行SELECT的查詢可使用並行查詢來執行,表加載自己能夠並行完成。
ALTER INDEX REBUILD:索引結構能夠並行重建。
ALTER TABLE MOVE:表能夠並行移動。
ALTER TABLE SPLIT|COALESCE PARTITION:單個表分區能夠並行地分解或合併。
ALTER INDEX SPLIT PARTITION:索引分區能夠並行地分解。
前4個命令還適用於單個的表/索引分區,能夠並行地MOVE一個表的單個分區。
並行DDL纔是Oracle中並行執行最突出的優勢。並行查詢主要是爲最終用戶設計的,那麼並行DDL則是爲DBA/開發人員設計的。
咱們只是使用一個「真實「表(而不是外部表),由此加載另外一個表,這相似於許多人在數據倉庫中使用暫存表(staging table)加載數據的作法:
(1) 使用某個抽取、轉換、加載(extract, transform, load, ETL)工具來建立輸入文件。
(2) 將執行輸入文件加載到暫存表。
(3) 使用對這些暫存表的查詢加載一個新表。
使用前面的BIG_TABLE(啓用了並行),將把這個表聯結到第二個表USER_INFO,其中包含ALL_USERS字典視圖中與OWNER相關的信息。將這個信息逆規範化爲一個平面結構。
首先建立USER_INFO表,啓用並行操做,而後生成這個表的統計信息:
scott@ORCL>create table user_info as select * from all_users; 表已建立。 scott@ORCL>alter table user_info parallel; 表已更改。 scott@ORCL>exec dbms_stats.gather_table_stats( user, 'USER_INFO' ); PL/SQL 過程已成功完成。 scott@ORCL>alter table big_table parallel; 表已更改。 scott@ORCL>explain plan for 2 create table new_table parallel 3 as 4 select a.*, b.user_id, b.created user_created 5 from big_table a, user_info b 6 where a.owner = b.username ; 已解釋。 scott@ORCL>select * from table(dbms_xplan.display); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------------------------------------- Plan hash value: 3867074464 -------------------------------------------------------------------------------- ----------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib | -------------------------------------------------------------------------------- ----------------------------------- | 0 | CREATE TABLE STATEMENT | | 11M| 1327M| 11266 (1)| 00:0 2:16 | | | | | 1 | PX COORDINATOR | | | | | | | | | | 2 | PX SEND QC (RANDOM) | :TQ10001 | 11M| 1327M| 6598 (1)| 00:0 1:20 | Q1,01 | P->S | QC (RAND) | | 3 | LOAD AS SELECT | NEW_TABLE | | | | | Q1,01 | PCWP | | |* 4 | HASH JOIN | | 11M| 1327M| 6598 (1)| 00:0 1:20 | Q1,01 | PCWP | | | 5 | PX RECEIVE | | 39 | 741 | 2 (0)| 00:0 0:01 | Q1,01 | PCWP | | | 6 | PX SEND BROADCAST | :TQ10000 | 39 | 741 | 2 (0)| 00:0 0:01 | Q1,00 | P->P | BROADCAST | | 7 | PX BLOCK ITERATOR | | 39 | 741 | 2 (0)| 00:0 0:01 | Q1,00 | PCWC | | | 8 | TABLE ACCESS FULL| USER_INFO | 39 | 741 | 2 (0)| 00:0 0:01 | Q1,00 | PCWP | | | 9 | PX BLOCK ITERATOR | | 11M| 1119M| 6585 (1)| 00:0 1:20 | Q1,01 | PCWC | | | 10 | TABLE ACCESS FULL | BIG_TABLE | 11M| 1119M| 6585 (1)| 00:0 1:20 | Q1,01 | PCWP | | -------------------------------------------------------------------------------- ----------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - access("A"."OWNER"="B"."USERNAME") 已選擇22行。
若是從第4步向下看,這些就是查詢(SELECT)部分。BIG_TABLE的掃描和與USER_INFO的散列聯結是並行執行的,並將各個子結果加載到表的某個部分中。每一個並行執行服務器完成其聯結和加載工做後,會把其結果發送給查詢協調器。在這裏,結果只是提示「成功「仍是」失敗「,由於工做已經執行。
僅此而已,利用並行直接路徑加載,使得問題變得很容易。對於這些操做,最重要的是要考慮如何使用空間(或不使用)。有一種稱爲區段截斷(extent trimming)的反作用至關重要。
並行DDL依賴於直接路徑操做。數據由一個操做(如CREATE TABLE AS SELECT)來建立新的區段,並直接寫入這些區段,數據直接從查詢寫到磁盤(放在這些新分配的區段中)。每一個並行執行服務器執行本身的部分CREATE TABLE AS SELECT工做,而且都會寫至本身的區段。INSERT /*+ APPEND */(直接路徑插入)會在一個段的HWM「之上「寫,每一個並行執行服務器再寫至其本身的一組區段,而不會與其餘並行執行服務器共享。所以,若是執行一個並行CREATE TABLE AS SELECT,並使用4個並行執行服務器來建立表,就至少有4個分區,可能還會更多。每一個並行執行服務器會分配其本身的區段,向其寫入,等填滿時,再分配另外一個新的區段,並行執行服務器不會使用由其餘並行執行服務器非品牌的區段。
UNIFORM SIZE是指表空間中的每一個區段大小老是徹底相同;AUTOALLOCATE則表示Oracle會使用一種內部算法來肯定每一個區段應該是多大。
若是使用UNIFORM SIZE,Oracle就不能執行區段截斷。全部區段都只能有唯一一種大小,不能有任何區段小於(或大於)這個大小。
AUTOALLOCATE區段支持區段截斷,AUTOALLOCATE方法使用一些特定大小的區段,並且能使用不一樣大小的空間。利用這種算法,一段時間後將容許使用表空間中的全部空閒空間。在字典管理的表空間中,若是請求一個100MB區段,假若Oracle只找到了99MB的自由區段,請求仍是會失敗(儘管離要求只差了一點點)。與字典管理表空間不一樣,有AUTOALLOCATE區段的本地管理表空間能夠更爲靈活。爲了試圖使用全部空閒空間,它能夠減少所請求的空間大小。
這裏將創建一個外部表,它能用於並行直接路徑加載。爲了討論區段截斷,咱們須要創建加載示例,而後在不一樣的條件下執行加載,並分析結果。
待續P762