《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

相关文章
相关标签/搜索