深入理解Oracle执行计划中的数据流动与并行查询机制
立即解锁
发布时间: 2025-08-23 01:40:38 阅读量: 1 订阅数: 6 

### 深入理解 Oracle 执行计划中的数据流动与并行查询机制
#### 1. 数据流动运算符(DFO)基础
数据流动运算符(DFO)在执行计划中是一个关键概念。它本质上是执行计划里的一个或多个行源操作,构成一个并行工作单元。为了更好地理解,我们来看一个仅含一个 DFO 的执行计划示例:
```sql
CREATE TABLE t5
PARTITION BY HASH (c1)
PARTITIONS 16
AS
SELECT ROWNUM c1, ROWNUM c2
FROM DUAL
CONNECT BY LEVEL <= 10000;
CREATE INDEX t5_i1
ON t5 (c2) local;
SELECT /*+ index(t5) parallel_index(t5) */
*
FROM t5
WHERE c2 IS NOT NULL;
```
执行计划如下:
| Id | Operation | Name | TQ |IN - OUT| PQ Distrib |
|-----|----------------------------------------------|----------|--------|--------|------------|
| 0 | SELECT STATEMENT | | | | |
| 1 | PX COORDINATOR | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10000 | Q1,00 | P->S | QC (RAND) |
| 3 | PX PARTITION HASH ALL | | Q1,00 | PCWC | |
| 4 | TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| T5 | Q1,00 | PCWP | |
| 5 | INDEX FULL SCAN | T5_I1 | Q1,00 | PCWP | |
这个示例首先创建了一个分区表 T5 以及相关的本地索引 T5_I1,然后对表进行查询,并通过提示指定使用索引访问 T5。由于索引全扫描不能使用块范围粒度,因此可以看到 `PX PARTITION HASH ALL` 操作,这表明使用了分区粒度。每个并行查询服务器会访问一个或多个分区,并对这些分区执行操作 4 和 5。当并行查询服务器从表中读取行时,这些行将被发送到查询协调器(QC),如操作 2 所示。QC 是最初存在的会话,除了接收并行查询服务器的输出外,还负责向并行查询服务器分配各种类型的粒度。
执行计划中 `IN - OUT` 列的内容也很重要。操作 3 显示 `PCWC`,表示与子操作并行组合;操作 5 显示 `PCWP`,表示与父操作并行组合;操作 4 则与父操作和子操作都进行了组合。这些信息可用于识别执行计划中每个 DFO 内的行源操作组。操作 2 的 `IN - OUT` 列显示 `P->S`,表示从并行到串行,即并行查询服务器正在向 QC 发送数据。
#### 2. 并行查询服务器集与 DFO 树
前面的示例只涉及一个 DFO,但执行计划可能包含多个 DFO,这些 DFO 的集合被称为 DFO 树。以下是一个包含多个 DFO 的并行查询示例:
```sql
BEGIN
FOR i IN 1 .. 4
LOOP
DBMS_STATS.gather_table_stats (
ownname => SYS_CONTEXT ('USERENV', 'CURRENT_SCHEMA')
,tabname => 'T' || i);
END LOOP;
END;
/
WITH q1
AS ( SELECT c1, COUNT (*) cnt1
FROM t1
GROUP BY c1)
,q2
AS ( SELECT c2, COUNT (*) cnt2
FROM t2
GROUP BY c2)
SELECT /*+ monitor optimizer_features_enable('11.2.0.3') parallel */
c1, c2, cnt1
FROM q1, q2
WHERE cnt1 = cnt2;
```
执行计划如下:
| Id | Operation | Name | TQ |IN - OUT| PQ Distrib |
|-----|-----------------------------|----------|--------|--------|------------|
| 0 | SELECT STATEMENT | | | | |
| 1 | PX COORDINATOR | | | | |
| 2 | PX SEND QC (RANDOM) | :TQ10003 | Q1,03 | P->S | QC (RAND) |
| 3 | HASH JOIN BUFFERED | | Q1,03 | PCWP | |
| 4 | VIEW | | Q1,03 | PCWP | |
| 5 | HASH GROUP BY | | Q1,03 | PCWP | |
| 6 | PX RECEIVE | | Q1,03 | PCWP | |
| 7 | PX SEND HASH | :TQ10001 | Q1,01 | P->P | HASH |
| 8 | PX BLOCK ITERATOR | | Q1,01 | PCWC | |
| 9 | TABLE ACCESS FULL | T1 | Q1,01 | PCWP | |
| 10 | PX RECEIVE | | Q1,03 | PCWP | |
| 11 | PX SEND BROADCAST | :TQ10002 | Q1,02 | P->P | BROADCAST |
| 12 | VIEW | | Q1,02 | PCWP | |
| 13 | HASH GROUP BY | | Q1,02 | PCWP | |
| 14 | PX RECEIVE | | Q1,02 | PCWP | |
| 15 | PX SEND HASH | :TQ10000 | Q1,00 | P->P | HASH |
| 16 | PX BLOCK ITERATOR | | Q1,00 | PCWC | |
| 17 | TABLE ACCESS FULL| T2 | Q1,00 | PCWP | |
收集缺失的对象统计信息后,执行了这个并行查询。使用 `optimizer_features_enable('11.2.0.3')` 提示是为了避免过早展示 12.1.0.1 版本的新特性。通过 `TQ` 列可以更轻松地识别 DFO,此计划中有四个不同的值,反映了四个 DFO。还可以查看每个 `PX SEND` 操作上方的操作,以了解每个 DFO 将数据发送到何处。
对于这样复杂的并行执行计划,绘制 DFO 树通常很有帮助。以下是该 DFO 树的简单示意:
```mermaid
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(Q1, 00):::process --> B(Q1, 01):::process
A --> C(Q1, 02):::process
B --> D(Q1, 03):::process
C --> D
D --> E(Coordinator):::startend
```
从图中可以看出,四个 DFO 中的三个将数据发送到另一个 DFO,而名为 `Q1, 03` 的 DFO(在执行计划中对应操作 2 到 6 以及操作 10)将数据发送到 QC。DFO 树既不是高度平衡的,也不是二叉树,树的叶子节点与根节点的距离各不相同,分支节点可能有一个或多个子节点。叶子节点通常是全表扫描等操作,而分支节点则通常是连接、聚合或排序操作。
为了支持多个并发的 DFO,Oracle 数据库引入了并行查询服务器集(P
0
0
复制全文
相关推荐










