《oracle編程藝術:深刻數據庫體系結構》之 十四 並行執行

所謂並行執行,是指可以將一個大型串行任務(任何DML,或者通常的DDL)物理地劃分爲多個較小的部分,這些較小的部分能夠同時獲得處理。算法

1 什麼時候使用並行執行

並行執行本質上是一個不可擴縮的解決方案,設計爲容許單個用戶或每一個特定SQL語句佔用數據庫的全部資源。若是某個特性容許一我的使用全部可用的資源,假若再容許兩我的使用這個特性,就會遇到明顯的競爭問題。數據庫

在應用並行執行以前,須要保證如下兩點成立:
必須有一個很是大的任務,如對50GB數據進行全面掃描。
必須有足夠的可用資源。在並行全面掃描50GB數據以前,你要確保有足夠的空閒CPU(以容納並行進程),還要有足夠的I/O通道,等等。服務器

2 並行查詢

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段分配區段。

3 並行DML

咱們能夠觀察到爲並行執行服務器建立的各個獨立事務。

因爲PDML採用的一種僞分佈式的實現,所以存在一些限制:

PDML操做期間不支持觸發器。由於觸發器可能會向更新增長大量開銷。

PDML期間,不支持某些聲明方式的引用完整性約束,由於表中的每一片(部分)會在單獨的會話中做爲單獨的事務進行修改。

在提交或回滾以前,不能訪問用PDML修改的表。

PDML不支持高級複製(由於複製特性的實現要基於觸發器)。

不支持延遲約束(也就是說,採用延遲模式的約束)。

若是表是分區的,PDML只可能在有位圖索引或LOB列的表上執行,並且並行度取決於分區數。在這種狀況下,沒法在分區內並行執行一個操做,由於每一個分區只有一個並行執行服務器來處理。

執行PDML時不支持分佈式事務。

PDML不支持聚簇表。

4 並行DDL

如下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/開發人員設計的。

4.1 並行DDL和使用外部表的數據加載

咱們只是使用一個「真實「表(而不是外部表),由此加載另外一個表,這相似於許多人在數據倉庫中使用暫存表(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)的反作用至關重要。

4.2 並行DDL和區段截斷

並行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

相關文章
相關標籤/搜索