并行查询的执行计划解读

来源:互联网 发布:2016年养殖业数据 编辑:程序博客网 时间:2024/06/05 22:37

 

in-out字段的pcwc或是pcwp代表什么意思?

一、执行计划里的(单独型)操作一般都是子操作在父操作前面执行,表现在并行查询语句的执行计划里的in_out字段(执行计划里当发生并行查询时才会出现的字段)就是pcwp,即子操作在父操作前面执行,亦即在一个进程集(同一个进程集的各个进程同时用于执行同一种操作,故而称该操作为并行操作)同一个进程可以执行完一个操作后再执行其父操作(这里,子操作和父操作有个执行先后顺序)

例如,

EXPLAIN PLAN FOR

  SELECT SUM(salary) FROM emp2 GROUP BY department_id;

SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());

 

--------------------------------------------------------------------------------------------------------

| Id  | Operation                | Name     | Rows  | Bytes | Cost (%CPU) |    TQ  |IN-OUT| PQ Distrib |

--------------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT         |          |   107 |  2782 |     3 (34)  |        |      |            |

|   1 |  PX COORDINATOR          |          |       |       |             |        |      |            |

|   2 |   PX SEND QC (RANDOM)    | :TQ10001 |   107 |  2782 |     3 (34)  |  Q1,01 | P->S | QC (RAND)  |

|   3 |    HASH GROUP BY         |          |   107 |  2782 |     3 (34)  |  Q1,01 | PCWP |            |

|   4 |     PX RECEIVE           |          |   107 |  2782 |     3 (34)  |  Q1,01 | PCWP |            |

|   5 |      PX SEND HASH        | :TQ10000 |   107 |  2782 |     3 (34)  |  Q1,00 | P->P | HASH       |

|   6 |       HASH GROUP BY      |          |   107 |  2782 |     3 (34)  |  Q1,00 | PCWP |            |

|   7 |        PX BLOCK ITERATOR |          |   107 |  2782 |     2 (0)   |  Q1,00 | PCWP |            |

|   8 |         TABLE ACCESS FULL| EMP2     |   107 |  2782 |     2 (0)   |  Q1,00 | PCWP |            |

--------------------------------------------------------------------------------------------------------

        从下往上,从右向左读时,先执行 TABLE ACCESS FULL,故而在其字段IN-OUTPCWP,再执行 PX BLOCK ITERATOR,故而在其字段IN-OUTPCWP,最后,执行 HASH GROUP BY   ,故而在其字段IN-OUTPCWP。

注释:

0、|   7 |        PX BLOCK ITERATOR |          |   107 |  2782 |     2 (0)   |  Q1,00 | PCWP |            |

其实,这里应该为PCWC。该例子是从别人博文上转载的,估计是有误的。不过拿来当例子说明正好。

1in-out字段的意思是in代表生产者,即作为生产者的进程向表队列里放入数据,out代表消费者,即作为消费者的进程向表队列里拿出数据。

2、同一个进程集的进程可以对应执行多个操作(操作指的是执行计划里显示的operation字段里的操作),比如,先执行操作A,再执行操作B同一个进程集的各个进程的行为是一样的,就是说同是进程集P里的进程EF,若E的行为是先执行操作A,再执行操作B,则F的行为也是先执行操作A,再执行操作B。即使F的行为的操作和E一样,但是先后顺序不一样,即先执行操作B,再执行操作A,那也是不一样的行为。

 

二、执行计划里的(单独型)操作若是父操作在子操作前面执行,则表现在并行查询语句的执行计划里的in_out字段(执行计划里当发生并行查询时才会出现的字段)就是pcwc,即父操作在子操作前面执行,亦即在一个进程集(同一个进程集的各个进程同时用于执行同一种操作,故而称该操作为并行操作)同一个进程可以执行完一个操作后再执行其子操作(这里,子操作和父操作有个执行先后顺序)。例如,

select /*+ parallel(t1 4) parallel(t2 4) */rownum, t1.idfrom t1, t2 where t1.id = t2.id;

------------------------------------------------------------------------------------------------------------------

| Id | Operation |Name | Rows | Bytes |Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |

------------------------------------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 100 | 600 | 5(20)| 00:00:01 | | | |

| 1 | COUNT | | | | | | | | |

| 2 | PX COORDINATOR | | | | | | | | |

| 3 | PX SEND QC (RANDOM) |:TQ10002 | 100 |600 | 5 (20)| 00:00:01 | Q1,02 | P->S | QC (RAND) |

|* 4 | HASH JOIN BUFFERED | | 100 | 600 | 5(20)| 00:00:01 | Q1,02 | PCWP | |

| 5 | PX RECEIVE | | 100 | 300 | 2(0)|00:00:01 | Q1,02 | PCWP | |

| 6 | PX SEND HASH | :TQ10000 | 100 | 300 |2 (0)| 00:00:01 | Q1,00 | P->P |HASH |

| 7 | PX BLOCK ITERATOR | | 100 | 300 | 2(0)| 00:00:01 | Q1,00 | PCWC | |

| 8 | TABLE ACCESSFULL | T1 | 100 | 300 | 2(0)| 00:00:01 | Q1,00 | PCWP | |

| 9 | PX RECEIVE | | 100 | 300 | 2(0)|00:00:01 | Q1,02 | PCWP | |

| 10 | PX SEND HASH | :TQ10001 | 100 | 300| 2 (0)| 00:00:01 | Q1,01 | P->P | HASH |

| 11 |PX BLOCK ITERATOR | | 100 | 300 | 2 (0)| 00:00:01 | Q1,01 | PCWC | |

| 12 | TABLE ACCESS FULL| T2 | 100 | 300 | 2 (0)|00:00:01 | Q1,01 | PCWP ||

------------------------------------------------------------------------------------------------------------------

 

        从下往上,从右向左读时,应先执行TABLE ACCESS FULL但是PX BLOCK ITERATOR的in_out字段里的值为PCWC,故而先执行PX BLOCK ITERATOR,再执行TABLE ACCESS FULL。执行好TABLE ACCESS FULL后,根据自己的in_out字段里的值为PCWP再去执行PX BLOCK ITERATOR,则发现PX BLOCK ITERATOR已经执行过,故而执行上上个操作。

 

注释:

  1、PX BLOCK ITERATOR:这个操作通常处于并行管道(即并行操作)的第一步,BLOCK ITERATOR把表分隔成多个(区域)块,每个(区域)块由涉及的并行服务器进程(slave process)中的一个去处理。(换句话说,在协调者进程QC预先对作用于同一个表的各个进程分配好各个进程负责的表区域后,各个进程执行BLOCK ITERATOR就是找到并确认标记下协调者进程QC分配给他们的区域。)

  一般地,BLOCK ITERATOR 和TABLE ACCESS FULL操作是成对出现的。

   前者是父操作,后者是子操作。

   前者的in_out字段里的值为PCWC,后者的in_out字段里的值为PCWP。也就是说,要先分割好区域后,各个进程才能在各自区域进行全表扫描。

2、除了按数据块分割表区域,即PX BLOCK ITERATOR外,还有一种方法来分割表区域:按表分区来分割表区域,即PX PARTION  ITERATOR。

3、PX BLOCK ITERATOR操作,是到目前为止本人有见过的其in_out字段值为PCWC的一种操作。

  

三、当发生并行查询时,其执行计划里的(单独型)子操作和父操作间的执行顺序还有另一种情况(除了子操作在父操作前面执行父操作在子操作前面执行这两种情况外),就是s->p或是p->pp->s

注释:

      判断是否有操作间的并行,看执行计划里的in-out字段是否有出现s->p或是p->pp->s,出现这些时name字段里总是会出现表队列的(TQ10002,其中1表示dfo_number((来自v$pq_tqstat的字段)),2表示tq_id(来自v$pq_tqstat的字段))。


总结:

并行操作间关系(执行计划中in-out部分,指明了操作中数据流的方向
p-s:并行进程集发送数据给串行进程(例如,协调者进程QC就是单个进程,或说串行进程)。
p-p:(有2slavesprocess时使用),一个并行操作将数据发送给另一个并行操作。

s-p:串行发送数据给并行,效率差(1.单一进程产生数据没有多个进程消费数据快,消费者花很多时间等数据而不是处理数据,2.串行执行操作和并行执行操作发送数据有一些不必要的通讯)。

 

PCWP在一个进程集里的同一个slave process(即同一个并行服务器进程)并行执行一个操作及其父操作(操作指的是执行计划里显示的operation字段里的操作,不是指的是sql语句的各个子句(这种就是所谓的sql语句级别上的操作),一个子句可以由多个这里的所谓操作组成。此操作时该操作对应的同一组内的进程间可以有交互,而没有组间通讯进程集里的进程间无通讯,即进程在执行该操作时还不到发送数据给表队列的时候。
PCWC:相同slaveprocess并行执行一个操作及其子操作,无通讯。


 

 


 ================================================================================================================================

说到同一个进程集的单个进程可以对应执行多个操作,那么在执行计划里怎么可以看出哪些操作是对应于同一个进程(换言之,一个进程会做哪些操作)呢?

 

同一个进程集的进程可以对应执行多个操作(操作指的是执行计划里显示的operation字段里的操作),比如,先执行操作A,再执行操作B同一个进程集的各个进程的行为是一样的,就是说同是进程集P里的进程EF,若E的行为是先执行操作A,再执行操作B,则F的行为也是先执行操作A,再执行操作B。即使F的行为的操作和E一样,但是先后顺序不一样,即先执行操作B,再执行操作A,那也是不一样的行为。

说到同一个进程集的单个进程可以对应执行多个操作,那么在执行计划里怎么可以看出哪些操作是对应于同一个进程(换言之,一个进程会做哪些操作)呢?我们要从执行计划里显示的(底部的)子操作开始看,看执行计划里该操作的in_out字段的值是pcwc或是pcwp这一类,还是s->p或是p->pp->s这一类的。属于后者的话,说明该操作对应一个进程。属于前者的话,该操作只是对应一个进程里的一步,还看父操作的in_out字端是pcwc或是pcwp这一类,还是s->p或是p->pp->s这一类的。属于后者的话,说明该进程对应两个操作。属于前者的话,还看其父操作的in_out字端是属于哪一类的。以此类推。总之,只要最终找到了哪个操作in_out字端是s->p或是p->pp->s这一类的,就可以确定同一个进程集的单个进程可以对应执行哪些操作了。

例如,

select/*+ parallel(t1 4) parallel(t2 4) */ rownum, t1.id from t1, t2where t1.id = t2.id;

 

------------------------------------------------------------------------------------------------------------------

| Id | Operation                | Name     | Rows | Bytes | Cost (%CPU)| Time    |    TQ  |IN-OUT| PQ Distrib |

------------------------------------------------------------------------------------------------------------------

|  0 | SELECT STATEMENT         |          |  100 |   600 |     5 (20)| 00:00:01 |        |      |            |

|  1 | COUNT                   |          |       |      |            |          |       |      |            |

|  2 |  PX COORDINATOR         |          |       |      |            |          |        |     |            |

|  3 |   PX SEND QC (RANDOM)   | :TQ10002|   100 |   600 |    5  (20)| 00:00:01 |  Q1,02 | P->S | QC (RAND)  |

|* 4 |    HASH JOIN BUFFERED   |          |  100 |   600 |     5 (20)| 00:00:01 |  Q1,02 | PCWP|            |

|  5 |     PX RECEIVE          |          |  100 |   300 |     2  (0)| 00:00:01 |  Q1,02 | PCWP|            |

|  6 |      PX SEND HASH       | :TQ10000|   100 |   300 |    2   (0)| 00:00:01 |  Q1,00 | P->P | HASH       |

|  7 |       PX BLOCK ITERATOR |         |   100 |   300 |    2   (0)| 00:00:01 |  Q1,00 | PCWC |            |

|  8 |        TABLE ACCESS FULL| T1       |   100|   300 |     2  (0)| 00:00:01 |  Q1,00 | PCWP|            |

|  9 |     PX RECEIVE          |          |  100 |   300 |     2  (0)| 00:00:01 |  Q1,02 | PCWP|            |

10 |      PX SEND HASH       | :TQ10001|   100 |   300 |    2   (0)| 00:00:01 |  Q1,01 | P->P | HASH       |

11 |       PX BLOCK ITERATOR |         |   100 |   300 |    2   (0)| 00:00:01 |  Q1,01 | PCWC |            |

12 |        TABLE ACCESS FULL| T2       |   100 |  300 |     2   (0)| 00:00:01 |  Q1,01 | PCWP |            |

------------------------------------------------------------------------------------------------------------------

1、Id从12到10的这些操作对应为我们取名叫A的进程集里的进程执行的操作。

2、Id从8到6的这些操作对应为我们取名叫B的进程集里的进程执行的操作。

3、我们再看id为9和id为5的操作,id为9和id为5的操作的in_out字段的值是属于pcwc或是pcwp这一类的。id为9和id为5的操作是并列的(因为他们向右缩进一样的距离),故而他们都是id为4的操作的子操作,id为4的操作就是他们的父操作。id为4的操作的in_out字段的值是pcwc或是pcwp这一类的。故而我们再看id为4的操作的父操作,即d为3的操作,该操作的in_out字段的值是属于s->p或是p->pp->s这一类的。所以id9543的操作,对应为我们取名叫C的进程集里的进程执行的操作。

4、 Id为2的操作是PX COORDINATOR,即协调者操作,它是一个串行操作,就是说该操作对应的进程集里只有一个进程,不是多个。我们取名该进程集叫C。如果一个进程集里有多个进程,那叫并行操作(的进程)。

图形化说明如下:


       我们从下文的DFO结构图(由v$pq_tqstat视图画出)看出,进程集A和进程集B其实是同一个进程集,即进程集(P4、P5、P6、P7)。也就是说对表T1和表T2的全表扫描等操作是由同一个进程集完成的。

 

补充:

1、凡是in_out字段的值是属于s->p或是p->pp->s这一类的操作都是px send 操作。凡是in_out字段的值是属于s->p或是p->pp->s这一类的操作对应的name字段都有一个值,且该值为一个表队列TQ

2、TQ字段里有值的操作,表明该操作有生产者的角色(不排除同时兼有消费者角色对另一个表队列),即该操作将数据放到TQ字段里的表队列上。


        我们从执行计划里,可以看出在并行化执行SQL语句时整个DFO结构图里哪些操作是对应于同一个进程。但是我们此时还不知道该进程是谁,该进程所属的进程集还有哪些进程。查看v$pq_tqstat就可以解决这个问题。

我们看上面例子的v$pq_tqstat

hlr@ORCL> select * from v$pq_tqstat order by dfo_number , tq_id , server_type;

 

DFO_NUMBER     TQ_ID SERVER_TYPE       NUM_ROWS      BYTES OPEN_TIME AVG_LATENCY     WAITS   TIMEOUTS PROCESS      INSTANCE

---------- ---------- ------------------------- ---------- ---------- ----------- ---------- ---------- --------------------

        1          0 Consumer                28        192          0           0         10         1 P002                1

        1          0 Consumer                26        184          0           0          9          1 P001                1

        1          0 Consumer                19        156          0           0         10          2 P000                1

        1          0 Consumer                27        188          0           0         10          3 P003                1

        1          0 Producer                 0         80          0           0          0          0 P007                1

        1          0 Producer                 0         80          0           0          0          0 P005                1

        1          0 Producer               100        480          0           0          2          1 P004                1

        1          0 Producer                 0         80          0           0          0          0 P006                1

        1          1 Consumer                28        192          0           0         10          1 P002                1

        1          1 Consumer                26        184          0           0          9          1 P001                1

        1          1 Consumer                19        156          0           0         10          3 P000                1

        1          1 Consumer                27        188          0           0         10          2 P003                1

        1          1 Producer               100        480          0           0          1          0 P004                1

        1          1 Producer                 0         80          0           0          0          0 P007                1

        1          1 Producer                 0         80          0           0          0          0 P005                1

        1          1 Producer                 0         80          0           0          0          0 P006                1

        1          2 Consumer               100        480          0           0          0          0 QC                  1

        1          2 Producer                27        128          0           0          0          0 P003                1

        1          2 Producer                26        124          0           0          0          0 P001                1

        1          2 Producer                28        132          0           0          0          0 P002                1

        1       2 Producer                19         96          0           0          0          0 P000                1

字段dfo_numbertq_id来标识一个表队列TQ

从上面的结果看,我们得出存在三个表队列TQ,分别TQ10TQ11TQ12。再看每个表队列,如表队列TQ10(即dfo_number=1tq_id=0的那些数据行),我们根据字段SERVER_TYPEProducerConsumer,可以将PROCESS字段的进程分成两个进程集。由此,可以画出DFO结构图,如下:

   



从上面的结果看,有一个DFOtree,三个TQ(table queue),并且p000,p001,p002不仅仅是消费者进程同时也是生产者进程。


同时,我们看到由于是两个表的连接操作(SQL语句级别的操作),所以TQ(1,0)TQ1,1)的生产者的进程集是一样的,即(P4P5P6P7)。

两个表的连接操作时,两个表的并行度不一样,则是以大的并行度为准。如,select/*+parallel(t1 2) parallel(t2 4) */rownum, t1.id from t1, t2where t1.id = t2.id;,则存在九个进程(1+2*4)。

 DFO结构图和下图是对应的:




 

 

注释:

1、DFO“Data FlowOperator”(数据流操作 过程,即从全表扫描获得的表的数据开始,对这些数据进行同时哪几种操作,即操作间的并行化。当然,操作内部也是并行化的)。

2、执行计划里的name字段里出现的表队列,如TQ10002,其中1表示dfo_number(来自v$pq_tqstat的字段),2表示tq_id(来自v$pq_tqstat的字段)。

 

 

================================================================================================================================
 

一般,一个SQL语句有存在几个子查询,则并行执行时就有几个QC(协调者进程),也即存在几个DFotree。

        一个DFO tree,对应一个没有有子查询的SQL语句。一个包括含有子查询的SQL语句,则一个SQL语句有存在几个子查询,则并行执行时就有几个QC(协调者进程),也即存在几个DFotree。在一个DFO tree(对应一个没有有子查询的SQL语句)里,并行执行的操作包含进程个数都是一样的,等于并行度。

例如,

select /*+ parallel(t1 4) parallel(v1 8 ) */ t1.id  from t1,       (select /*+ parallel(t1 4) parallel(t2 4) */         rownum, t1.id          from t1, t2         where t1.id = t2.id) v1 where t1.id = v1.id;
它的执行计划:

-------------------------------------------------------------------------------------------------------------------------| Id  | Operation                       | Name     | Rows  | Bytes | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |-------------------------------------------------------------------------------------------------------------------------|   0 | SELECT STATEMENT                |          |   100 |   600 |     7  (15)| 00:00:01 |        |      |            ||   1 |  PX COORDINATOR                 |          |       |       |            |          |        |      |            ||   2 |   PX SEND QC (RANDOM)           | :TQ20002 |   100 |   600 |     7  (15)| 00:00:01 |  Q2,02 | P->S | QC (RAND)  ||*  3 |    HASH JOIN                    |          |   100 |   600 |     7  (15)| 00:00:01 |  Q2,02 | PCWP |            ||   4 |     PX RECEIVE                  |          |   100 |   300 |     2   (0)| 00:00:01 |  Q2,02 | PCWP |            ||   5 |      PX SEND HASH               | :TQ20001 |   100 |   300 |     2   (0)| 00:00:01 |  Q2,01 | P->P | HASH       ||   6 |       PX BLOCK ITERATOR         |          |   100 |   300 |     2   (0)| 00:00:01 |  Q2,01 | PCWC |            ||   7 |        TABLE ACCESS FULL        | T1       |   100 |   300 |     2   (0)| 00:00:01 |  Q2,01 | PCWP |            ||   8 |     BUFFER SORT                 |          |       |       |            |          |  Q2,02 | PCWC |            ||   9 |      PX RECEIVE                 |          |   100 |   300 |     5  (20)| 00:00:01 |  Q2,02 | PCWP |            ||  10 |       PX SEND HASH              | :TQ20000 |   100 |   300 |     5  (20)| 00:00:01 |        | S->P | HASH       ||  11 |        VIEW                     |          |   100 |   300 |     5  (20)| 00:00:01 |        |      |            ||  12 |         COUNT                   |          |       |       |            |          |        |      |            ||  13 |          PX COORDINATOR         |          |       |       |            |          |        |      |            ||  14 |           PX SEND QC (RANDOM)   | :TQ10002 |   100 |   600 |     5  (20)| 00:00:01 |  Q1,02 | P->S | QC (RAND)  ||* 15 |            HASH JOIN BUFFERED   |          |   100 |   600 |     5  (20)| 00:00:01 |  Q1,02 | PCWP |            ||  16 |             PX RECEIVE          |          |   100 |   300 |     2   (0)| 00:00:01 |  Q1,02 | PCWP |            ||  17 |              PX SEND HASH       | :TQ10000 |   100 |   300 |     2   (0)| 00:00:01 |  Q1,00 | P->P | HASH       ||  18 |               PX BLOCK ITERATOR |          |   100 |   300 |     2   (0)| 00:00:01 |  Q1,00 | PCWC |            ||  19 |                TABLE ACCESS FULL| T1       |   100 |   300 |     2   (0)| 00:00:01 |  Q1,00 | PCWP |            ||  20 |             PX RECEIVE          |          |   100 |   300 |     2   (0)| 00:00:01 |  Q1,02 | PCWP |            ||  21 |              PX SEND HASH       | :TQ10001 |   100 |   300 |     2   (0)| 00:00:01 |  Q1,01 | P->P | HASH       ||  22 |               PX BLOCK ITERATOR |          |   100 |   300 |     2   (0)| 00:00:01 |  Q1,01 | PCWC |            ||  23 |                TABLE ACCESS FULL| T2       |   100 |   300 |     2   (0)| 00:00:01 |  Q1,01 | PCWP |            |-------------------------------------------------------------------------------------------------------------------------                                                                                                                     
Information from v$pq_tqstat:     
hlr@ORCL> select * from v$pq_tqstat  order by dfo_number , tq_id , server_type;DFO_NUMBER      TQ_ID SERVER_TYPE       NUM_ROWS      BYTES  OPEN_TIME AVG_LATENCY      WAITS   TIMEOUTS PROCESS      INSTANCE---------- ---------- --------------- ---------- ---------- ---------- ----------- ---------- ---------- ---------- ----------         1          0 Consumer                27        128          0           0         14          8 P003                1         1          0 Consumer                19         96          0           0         12          6 P000                1         1          0 Consumer                26        124          0           0         12          6 P001                1         1          0 Consumer                28        132          0           0         14          8 P002                1         1          1 Consumer                27        188          0           0         13          7 P003                1         1          1 Consumer                26        184          0           0         14          9 P001                1         1          1 Consumer                28        192          0           0         11          6 P002                1         1          1 Consumer                19        156          0           0         14          9 P000                1         1          1 Producer                 0         80          0           0          0          0 P006                1         1          1 Producer               100        480          0           0          1          0 P004                1         1          1 Producer                 0         80          0           0          0          0 P005                1         1          1 Producer                 0         80          0           0          0          0 P007                1         1          2 Producer                26        124          0           0          0          0 P001                1         1          2 Producer                19         96          0           0          0          0 P000                1         1          2 Producer                28        132          0           0          0          0 P002                1         1          2 Producer                27        128          0           0          0          0 P003                1         2          0 Consumer                26        184          0           0         14          7 P009                1         2          0 Consumer                19        156          0           0         15          8 P008                1         2          0 Consumer                28        192          0           0         13          7 P010                1         2          0 Consumer                27        188          0           0         13          8 P011                1         2          0 Producer               100        480          0           0          2          1 P016                1         2          0 Producer                 0         80          0           0          0          0 P013                1         2          0 Producer               100        480          0           0 4294967242 4294967282 QC                  1         2          0 Producer                 0         80          0           0          0          0 P014                1         2          0 Producer                 0         80          0           0          0          0 P012                1         2          1 Consumer                19        156          0           0         14          8 P008                1         2          1 Consumer                27        188          0           0         14          8 P011                1         2          1 Consumer                28        192          0           0         16          7 P010                1         2          1 Consumer                26        184          0           0         13          7 P009                1         2          1 Producer               100        480          0           0          1          0 P016                1         2          1 Producer                 0         80          0           0          0          0 P014                1         2          1 Producer                 0         80          0           0          0          0 P012                1         2          1 Producer                 0         80          0           0          0          0 P013                1         2          2 Consumer               100        480          0           0          2          1 QC                  1         2          2 Consumer               100        480          0           0          4          2 QC                  1         2          2 Producer                28        132          0           0          0          0 P010                1         2          2 Producer                27        128          0           0          0          0 P011                1         2          2 Producer                19         96          0           0          0          0 P008                1         2          2 Producer                26        124          0           0          0          0 P009                1

由上面v$pq_tqstat的结果画出DFO结构图:

       注释:Questions is: there are two QC in TQ(2,2), which have different waits and timeouts in v$pq_tqstat. And the TQ(1,0) have no producers in the v$pq_tqstat, I just add it for completion.
由此,看出上面的sql 语句有两个DFO trees。

        同时,我们可以看出上面的sql语句并行化执行时的并行服务进程(即slave process)有16个,即对表T1有4个,对表T2有4个,对表V1有8个,共16个。该sql语句里,parallel(t1 4)出现了两次,但是它都是针对同一个表的,所以要当一次算。因此,我们发现并行度是针对表这个对象来讲的,不是说parallel提示每次出现都要增加一些并行进程个数。

       还有,一个sql语句里两次出现的parallel提示里对同一个表的并行度设置不一样,则大的并行度为准。例如,
     
select /*+ parallel(t1 6) parallel(v1 8 ) */ t1.id  from t1,       (select /*+ parallel(t1 4) parallel(t2 4) */         rownum, t1.id          from t1, t2         where t1.id = t2.id) v1 where t1.id = v1.id;
则表TI的并行度为6,不是4.(在oracle 11g R2上测试,是如此的)

疑问解答:
0、首先,说明本文中的例子:
select /*+ parallel(t1 4) parallel(v1 8 ) */ t1.id  from t1,       (select /*+ parallel(t1 4) parallel(t2 4) */         rownum, t1.id          from t1, t2         where t1.id = t2.id) v1 where t1.id = v1.id;
是转载自   http://os2ora.com/en/how-to-have-multiple-dfo-trees/    。

         不知道它是在oracle什么版本上做的实验,因为它通过select * from v$pq_tqstat  order by dfo_number , tq_id , server_type; 语句所得结果和本人在oracle 11g R2上所得结果是不一样的。在oracle 11g R2上所得结果,表明该SQL语句并行化执行时,共有24个并行服务进程(slave process)。
      我们分析下为什么会有24个并行服务进程(slave process)。
       首先,我们要知道两个原则:一个是在一个SQL语句(包括含有子查询的SQL语句)中同一个表的并行度设置不一样,则大的并行度为准;一个是在一个SQL语句(包括含有子查询的SQL语句)中两个表的连接操作时,两个表的并行度不一样,则是以大的并行度为准
       接下来,我们分析下为什么会有24个并行服务进程(slave process):
      首先依据第一个原则,表T1和T2的并行度为4,表V1的并行度为8,。接着依据第二个原则,子查询里两个表的并行度为4,因为子查询里的语句涉及到两个操作,分别是全表扫描和表的关联操作,依据“并行度就是指的是操作内部有几个进程并行化执行”的原则,所以2*4=8。依据第二个原则,该sql语句的外层两个表的并行度为8,也因为该sql语句的外层语句涉及到两个操作,分别是全表扫描和表的关联操作,依据“并行度就是指的是操作内部有几个进程并行化执行”的原则,所以2*8=16。所以,共有8+16=24个进程。
     注释:
1、下面的例子就是在上面sql语句上将原来parallel(t1 4)改为parallel(t1 5):
select /*+ parallel(t1 5) parallel(v1 8 ) */ t1.id  from t1,       (select /*+ parallel(t1 4) parallel(t2 4) */         rownum, t1.id          from t1, t2         where t1.id = t2.id) v1 where t1.id = v1.id;

结果共有26个并行服务进程(slave process)。这也就证明了上面提到的两个原则。
一个DFO tree,对应一个没有有子查询的SQL语句。一个包括含有子查询的SQL语句,则一个SQL语句有存在几个子查询,则并行执行时就有几个QC(协调者进程),也即存在几个DFotree。在一个DFO tree(对应一个没有有子查询的SQL语句)里,并行执行的操作包含进程个数都是一样的,等于并行度。如下图所示:
 
全表扫描操作(即进程集(p4、p5、p6、p7)所执行的操作)共有4个进程,表的关联操作(即进程集(p0、p1、p2、p3)所执行的操作)也是共有4个进程。这两个并行(即同时执行)的操作都是由4个进程来执行的。

2、具体一个SQL语句并行时到底有几个并行执行的操作,看执行计划即可。执行计划里的一个操作对应有几个进程并行执行,查v$pq_tqstat视图。虽然说有了经验后,不看执行计划和v$pq_tqstat视图,也能知道一个SQL语句并行化执行时有几个操作,操作对应的进程集里有几个进程,但是查看下还是比较保险不会错的,比如,本人开始时就是不知道在存在表的连接操作时,对两个表的全表扫描访问是由同一个进程集来完成的,还以为是两个不同的进程集呢,在查看了v$pq_tqstat视图后才知道的。并行时全表扫描的过程:比如p4先扫描表t1上自己负责的区域,扫描完后发送给表队列TQ(1,0),接着再扫描表t2上自己负责的区域,扫描完后发送给表队列TQ(1,1).



1、
一个sql语句里对两个表的连接操作时两个表的并行度设置不一样,看哪个?

同时,我们看到由于是两个表的连接操作(SQL语句级别的操作),所以TQ(1,0)TQ1,1)的生产者的进程集是一样的,即(P4P5P6P7)?

两个表的连接操作时,两个表的并行度不一样,则是以大的并行度为准?

那么,

select /*+ parallel(t1 4) parallel(v1 8 ) */ t1.id  from t1,       (select /*+ parallel(t1 4) parallel(t2 4) */         rownum, t1.id          from t1, t2         where t1.id = t2.id) v1 where t1.id = v1.id;
这个语句里,parallel(v1 8 ),即表V1的并行度为8,而该语句的DFO结构图来看的话,进程集(指的是(P12、P13、P14、P16)里的进程个数(即并行度)只有4个?

答:
          这个例子是从别人的博文上转载的,不知道它是在oracle什么版本上做的实验,因为它通过select * from v$pq_tqstat  order by dfo_number , tq_id , server_type; 语句所得结果和本人在oracle 11g R2上所得结果是不一样的。在oracle 11g R2上所得结果,表明该SQL语句并行化执行时,共有24个并行服务进程(slave process)。
        再比如,本人在oracle 11g R2上测试,select/*+parallel(t1 2) parallel(t2 4) */rownum, t1.id from t1, t2where t1.id = t2.id;,则存在九个进程(1(协调进程)+2*4并行服务进程))。
        所以,两个表的连接操作时,两个表的并行度不一样,则是以大的并行度为准

一个sql语句里同一个表的并行度设置不一样,看哪个?

一个sql语句里两次出现的parallel提示里对同一个表的并行度设置不一样,则大的并行度为准。例如,
     

select /*+ parallel(t1 6) parallel(v1 8 ) */ t1.id  from t1,       (select /*+ parallel(t1 4) parallel(t2 4) */         rownum, t1.id          from t1, t2         where t1.id = t2.id) v1 where t1.id = v1.id;
则表TI的并行度为6,不是4。该sql语句并行化执行时,共有28并行服务进程在oracle 11g R2上测试


 2、一个DFO tree(对应一个没有有子查询的SQL语句)里,在并行度就是指的是操作内部有几个进程并行化执行,如一个全表扫描操作有几个进程并行化执行

select /*+ parallel(t1 4) parallel(v1 8 ) */ t1.id  from t1,       (select /*+ parallel(t1 4) parallel(t2 4) */         rownum, t1.id          from t1, t2         where t1.id = t2.id) v1 where t1.id = v1.id;

这个语句里,parallel(v1 8 ),即表V1的并行度为8,而该语句的DFO结构图来看的话,全表扫描操作的进程集(指的是(P12、P13、P14、P16)里的进程个数(即并行度)只有4个?

答:
          这个例子是从别人的博文上转载的,不知道它是在oracle什么版本上做的实验,因为它通过select * from v$pq_tqstat  order by dfo_number , tq_id , server_type; 语句所得结果和本人在oracle 11g R2上所得结果是不一样的。在oracle 11g R2上所得结果,表明该SQL语句并行化执行时,共有24个并行服务进程(slave process)。
其中,因为子查询里的语句涉及到两个操作,分别是全表扫描和表的关联操作,,所以2*4=8。该sql语句的外层两个表的并行度为8,也因为该sql语句的外层语句涉及到两个操作,分别是全表扫描和表的关联操作,所以2*8=16。所以,共有8+16=24个进程。

            因此,一个DFO tree(对应一个没有子查询的SQL语句)里,并行度就是指的是操作内部有几个进程并行化执行

3、

Select/*+parallel(t1 4) */加上Group by时,会新增一组由四个进程组成的进程集用于分组操作,加上原来全表扫描操作的四个进程和一个协调进程,共1+2*4=9.

Oraderbyoracle11gR2上不会如此,还是只有5个进程。

 


总结:

为了说明简单,这里以没有包含子查询的SQL语句为例。

SQL语句以并行化执行和没有以并行化执行的相同地方在于:

SQL语句没有以并行化执行时有几个操作,一般以并行化执行也是有几个操作,即两者的操作是一样的。

例如,select /*+ parallel(t1 4) parallel(t2 4) */ rownum, t1.id from t1, t2 where t1.id = t2.id;和select rownum, t1.id from t1, t2 where t1.id = t2.id;两个语句,在执行计划里,都是由全表扫描和表的关联操作组成。

SQL语句以并行化执行和没有以并行化执行的区别在于:

SQL语句没有以并行化执行时的那几个操作是以串行顺序执行的,即执行完子操作后才能执行父操作,有一个先后执行顺序。而且,还有,就是一个操作也是由一个进程来执行的。

以并行化执行的那几个操作是以并行顺序执行的,即那几个操作是同时执行的,确切地说,是同时有不同几个进程集来执行不同的操作。还有,就是一个操作是由一个进程集里放入多个进程同时来执行的。

例如,select /*+ parallel(t1 4) parallel(t2 4) */ rownum, t1.id from t1, t2 where t1.id = t2.id;和select rownum, t1.id from t1, t2 where t1.id = t2.id;两个语句。

前者,全表扫描和表的关联操作同时执行,两者间通过表队列(table queue)交换数据。全表扫描操作由进程P4、P5、P6、P7来同时执行,表的关联操作由进程P0、P1、P2、P3来同时执行。

前者,全表扫描执行后再执行表的关联操作,两者间通过表队列(table queue)交换数据。两个操作都是由一个进程(即服务器进程)来执行的。

附加1:

在执行计划有关于PX开头的步骤,下面,我们进行一下介绍。

PX BLOCK ITERATOR:这个操作通常处于并行管道的第一步,BLOCK ITERATOR把表分隔成多个(区域)块,每个(区域)块由涉及的并行服务器进程(slave process)中的一个去处理。
 
 
PX SEND RANGE:这个操作表明数据正在根据范围值来从一个并行进程发送到另一个并进程。
PX RECEIVE:表示来自另一个进程的数据正在被一个并行进程接收。
PX SEND QC:这是给并行查询协调进程的一个发送操作。
PX COORDINATOR:这个步骤表明并行查询协调进程正在从并行流中接收数据并返回给SQL语句。
关于IN-OUT项的说明:
P->P(parallel_to_parallel):表示并行处理传递结果到并行进程的第二个集合,例如,并行扫描进程可以传递给并行排序进程。
P->S(parallel_to_serial):这个结果通常发生在查询的最上层,将结果并行地提供给查询协调者。
PCWP(parallel_combined_with_parent):这个步骤是以并行的方式执行的,父步骤或子步骤也由同一个进程并行运行。 例如在一个并行嵌套循环连接中,并行查询进程扫描驱动表,同时也发出对连接表的索引查找。
PCWC(parallel_combined_with_child):含义同PCWP类似。
S->P(parallel_from_serial):串行操作把结果传给并行进程的集合,如果出现这一项,可能暗示并行语句有一个串行的瓶颈, 可能在等待串行处理。
关于“PQ Distrib”项(分发选项)的介绍:
RANGE:根据值的范围来分发记录。当使用并行排序操作时,这是一个很典型的选项。
HASH:根据值的散列,把记录分发到并行查询的子进程。适合连接和GROUP BY操作。
RANDOM:记录被随机分配给进行查询的子进程。
ROUND ROBIN:以循环的方式把记录每次一个地分发给子进程。

/*****对SQL使用并行化时,使用SQL trace进行跟踪时,相对比较困难一缜,这是因为在并行中每个进程都有自己的跟踪文件,而且由于这些进程被共享在所有并行化的SQL和会话期间,除了我们要的那部分数据外,还包括了其他SQL的信息。我们可以通过以一下些步骤,仍然能够跟踪并行执行。*****/


附加2:

1、说明并行执行计划中特有的IN-OUT列的含义(指明了操作中数据流的方向)
Parallel to Serial
P->S:表示一个并行操作向一个串行操作发送数据,通常是将并行结果发送给并行

调度进程QC进行汇总例如 PX SEND QC (RANDOM)

Serialto ParallelS->P:表示一个串行操作向一个并行操作发送数据,如果select部分是串行操作,就会出现这个情况

Parallelto ParallelP->P):表示一个并行操作向另一个并行操作发送数据,一般是并行父进程与并行子进程之间的数据交流

Parallel Combined with parent(PCWP):数据在同一组的并行进程之间传递
Parallel Combined withChild(PCWC):数据在不同组的并行进程之间传递


2、

PCWP---并行与父操作合并,此为同一组内的进程交互,因此没有组间通讯

PCWC---并行与子操作合并,也为同组进程交互,没有组间通讯

3、并发查询的执行计划是一个树形结构(DFO),每个树上的DFO节点是一个sql操作过程,并且能把该操作过程能指派到一个query slave进程中。


 

参见:

操作内部和操作之间的并行处理

 

参考博文:

http://blog.163.com/donfang_jianping/blog/static/1364739512013230111042597/       (Oracle 并行处理)

http://www.cnblogs.com/xd502djj/archive/2012/04/26/2471526.html

http://blog.itpub.net/22664653/viewspace-721381/

http://os2ora.com/en/how-to-have-multiple-dfo-trees/

 

0 0
原创粉丝点击