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

What is the difference between NOPARALLEL and PARALLEL 1 in Oracle?

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

CREATE TABLE t0 (i NUMBER) NOPARALLEL;
CREATE TABLE t1 (i NUMBER) PARALLEL 1;
CREATE TABLE t2 (i NUMBER) PARALLEL 2;

它们在数据字典中显示为

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

TABLE_NAME  DEGREE
T0               1 <==
T1               1 <==
T2               2

不过documentation说的很清楚

NOPARALLEL: Specify NOPARALLEL for serial execution. This is the default.

PARALLEL integer: Specification of integer indicates the degree of parallelism, which is the number of parallel threads used in the parallel operation. Each parallel thread may use one or two parallel execution servers.

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

顺便说一句,?/rdbms/admin/dcore.bsq 中的 CREATE TABLE sys.tab$ 语句有注释

/* 
 * 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 */

NOPARALLELPARALLEL 1 之间没有区别 - 这些选项的存储方式和行为方式相同。这是一个文档错误,因为 Oracle 永远不会为 PARALLEL 1 使用两个并行执行服务器。我们可以通过查看 V$PX_PROCESS 和理解 producer/consumer 并行模型来测试这种情况。

如何测试并行性

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

select *
from gv$px_process
where status <> 'AVAILABLE';

Producer/Consumer 型号

如果您想完全理解 Oracle 并行性,VLDB 和分区指南的使用并行执行一章值得一读。特别是,阅读手册的 Producer/Consumer Model 部分以了解 Oracle 何时将并行服务器的数量加倍。

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

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

测试

创建这三个 table:

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;

运行 以下查询,当它们 运行 正在使用单独的会话 运行 之前针对 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;

请注意 NOPARALLELPARALLEL 1 table 的工作方式完全相同,它们都不使用任何并行服务器。但是PARALLEL 2table会导致结果排序时并行执行服务器的数量翻倍

为什么 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;

如果我们必须使用 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;