所谓并行执行,是指可以将一个大型串行任务(任何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