Oracle 中的 NOPARALLEL 和 PARALLEL 1 有什么区别?

wol*_*lφi 7 oracle parallel-processing

NOPARALLEL和 和有PARALLEL 1什么区别?如果我像这样创建三个表:

CREATE TABLE t0 (i NUMBER) NOPARALLEL;
CREATE TABLE t1 (i NUMBER) PARALLEL 1;
CREATE TABLE t2 (i NUMBER) PARALLEL 2;
Run Code Online (Sandbox Code Playgroud)

它们在数据字典中显示为

SELECT table_name, degree FROM user_tables WHERE table_name IN ('T0','T1','T2');

TABLE_NAME  DEGREE
T0               1 <==
T1               1 <==
T2               2
Run Code Online (Sandbox Code Playgroud)

文件,但规定很清楚

NOPARALLEL:为串行执行指定 NOPARALLEL。这是默认设置。

PARALLEL integer : integer 的规范表示并行度,即并行操作中使用的并行线程数。每个并行线程可以使用一个或两个并行执行服务器。

所以,NOPARALLEL肯定是串行的,而PARALLEL 1使用一个线程,可能使用一个或两个并行服务器???但是,当数据字典为两者存储相同的值 1 时,Oracle 如何区分它们呢?

顺便说一句,CREATE TABLE sys.tab$?/rdbms/admin/dcore.bsq 中的声明有评论

/* 
 * Legal values for degree, instances: 
 *     NULL (used to represent 1 on disk/dictionary and implies noparallel), or
 *     2 thru EB2MAXVAL-1 (user supplied values), or
 *     EB2MAXVAL (implies use default value) 
 */
degree        number,      /* number of parallel query slaves per instance */
instances     number,        /* number of OPS instances for parallel query */
Run Code Online (Sandbox Code Playgroud)

Jon*_*ler 5

NOPARALLEL和之间没有区别PARALLEL 1- 这些选项的存储方式和行为方式相同。这是一个文档错误,因为 Oracle 永远不会为PARALLEL 1. 我们可以通过查看V$PX_PROCESS和理解并行的生产者/消费者模型来测试这种情况。

如何测试并行性

有很多方法可以衡量并行度,例如执行计划或查看GV$SQL.USERS_EXECUTING. 但最好的方法之一是使用视图GV$PX_PROCESS。以下查询将显示当前使用的所有并行服务器:

select *
from gv$px_process
where status <> 'AVAILABLE';
Run Code Online (Sandbox Code Playgroud)

生产者/消费者模型

如果您想全面了解 Oracle 并行性,则 VLDB 和分区指南的使用并行执行一章值得一读。特别是,阅读手册的生产者/消费者模型部分以了解 Oracle 何时将并行服务器的数量增加一倍。

简而言之 - 每个操作都是单独并行执行的,但这些操作需要相互馈送数据。全表扫描可能使用 4 个并行服务器读取数据,但 group by 或 order by 操作需要另外 4 个并行服务器对数据进行散列或排序。虽然并行度为4,但并行服务器的数量为8。这就是SQL Language Reference 中“每个并行线程可能使用一个或两个并行执行服务器”这句话的意思。

Oracle 不只是随机地将服务器数量增加一倍。加倍只发生在某些操作上,比如 an ORDER BY,这让我们可以精确地测试 Oracle 何时启用并行性。下面的测试表明 Oracle 不会将 1 个并行线程加倍到 2 个并行服务器。

测试

创建这三个表:

create table table_noparallel noparallel as select level a from dual connect by level <= 1000000;
create table table_parallel_1 parallel 1 as select level a from dual connect by level <= 1000000;
create table table_parallel_2 parallel 2 as select level a from dual connect by level <= 1000000;
Run Code Online (Sandbox Code Playgroud)

运行以下查询,并在它们运行时使用单独的会话来针对GV$PX_PROCESS. 在这里使用 IDE 可能会有所帮助,因为您只需检索前 N 行并保持游标打开即可算作使用并行服务器。

--0 rows:
select * from table_noparallel;

--0 rows:
select * from table_noparallel order by 1;

--0 rows:
select * from table_parallel_1;

--0 rows:
select * from table_parallel_1 order by 1;

--2 "IN USE":
select * from table_parallel_2;

--4 "IN USE":
select * from table_parallel_2 order by 1;
Run Code Online (Sandbox Code Playgroud)

请注意,表NOPARALLELPARALLEL 1表的工作方式完全相同,并且都没有使用任何并行服务器。但是该PARALLEL 2表在对结果进行排序时会导致并行执行服务器的数量翻倍。

为什么PARALLEL 1甚至允许?

为什么 Oracle 不强制该PARALLEL子句只接受大于 1 的数字并避免这种歧义?毕竟,编译器已经实施了限制;该子句PARALLEL 0将引发错误“ORA-12813:PARALLEL 或 DEGREE 的值必须大于 0”。

我猜想允许数值表示“无并行性”可以使一些代码更简单。例如,我编写了计算 DOP 并作为变量传递的程序。如果只使用数字,则动态 SQL 非常简单:

v_sql := 'create or replace table test1(a number) parallel ' || v_dop;
Run Code Online (Sandbox Code Playgroud)

如果我们必须使用NOPARALLEL,代码会变得有点难看:

if v_dop = 1 then
    v_sql := 'create or replace table test1(a number) noparallel';
else
    v_sql := 'create or replace table test1(a number) parallel ' || v_dop;
end if;
Run Code Online (Sandbox Code Playgroud)

  • 这就是我喜欢 stackoverflow 的原因!非常好的回答,非常好的解释,非常感谢! (4认同)