Oracle并行

1.Oracle服务器维护一个可用于并行操作的并行子进程池。数据库配置参数parallel_max_servers integer  和 parallel_min_servers integer 决定这个池的初始数和最大数,如果当前没有足够的子进程是活跃的,但池还没有达到最大值,则oracle将创建更多的子进程,经过一个设定的不活动周期,子进程将被关闭

SQL> show parameter parallel;
NAME         TYPE  VALUE
------------------------------------ ----------- fast_start_parallel_rollback      string  LOW
parallel_adaptive_multi_user      boolean  TRUE
parallel_automatic_tuning      boolean  FALSE
parallel_degree_limit       string  CPU
parallel_degree_policy       string  MANUAL
parallel_execution_message_size      integer  16384
parallel_force_local       boolean  FALSE
parallel_instance_group       string
parallel_io_cap_enabled       boolean  FALSE
parallel_max_servers       integer  120
parallel_min_percent       integer  0
parallel_min_servers       integer  8
parallel_min_time_threshold      string  AUTO
parallel_server        boolean  TRUE
parallel_server_instances      integer  2
parallel_servers_target       integer  64
parallel_threads_per_cpu      integer  2
recovery_parallelism       integer  0

2.查询目前用了多少个并行进程,还有多少个并行进程可用:

SQL> SELECT * FROM V$PX_PROCESS_SYSSTAT;
STATISTIC                    VALUE
---------------------------------------------------------------------Servers In Use                 0
Servers Available                8
Servers Started                 8
Servers Shutdown                0
Servers Highwater                3
Servers Cleaned Up                0
Server Sessions                 3
Memory Chunks Allocated                4
Memory Chunks Freed                0
Memory Chunks Current                4
Memory Chunks HWM                4
Buffers Allocated               23
Buffers Freed                15
Buffers Current                 8
Buffers HWM                20
15 rows selected.

3.确定并行度,最优的并行度对于活得好的并行度性能至关重要,oracle根据下面的规则来确定并行度,如果指定或请求并行执行,但没有指定并行度,默认的并行度被设置为系统CPU核数的两倍,对RAC系统,并行度设置为整个集群的cpu核数的两倍

SQL> show parameter cpu;
NAME         TYPE  VALUE
------------------------------------ ----------- --------------------cpu_count        integer  4
parallel_threads_per_cpu      integer  2
resource_manager_cpu_allocation      integer  4

 4.V$PQ_TQSTAT视图:

即使有explan_PLAN和sql_traces输出,还是很难准确地解释并行查询的如何执行的,例如,实际的并行度是什么,每个并行服务进程都做了哪些工作?v$pq_tqstat视图包含了有关并行查询服务器的每个集合间传输的信息,包括发送和接收的行数。不过这个视图仅对发送并行查询的会话和最近执行过的查询是可见的。这些限制了它在产品中的使用,但在调优并行查询事,它有作用的。

SELECT /*+ parallel */
 prod_id, SUM(amount_sold)
  FROM sales
 GROUP BY prod_id
  5   ORDER BY 2 DESC;

72 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 3876052276
-------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation      | Name     | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |    TQ |IN-OUT| PQ Distrib |
-------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |        |    72 |   648 |   317 (10)| 00:00:01 |       |       | |      |     |
|   1 |  PX COORDINATOR      |        |       |       |     |        |       |       | |      |     |
|   2 |   PX SEND QC (ORDER)     | :TQ10002 |    72 |   648 |   317 (10)| 00:00:01 |       |       |  Q1,02 | P->S | QC (ORDER) |
|   3 |    SORT ORDER BY     |        |    72 |   648 |   317 (10)| 00:00:01 |       |       |  Q1,02 | PCWP |     |
|   4 |     PX RECEIVE      |        |    72 |   648 |   317 (10)| 00:00:01 |       |       |  Q1,02 | PCWP |     |
|   5 |      PX SEND RANGE     | :TQ10001 |    72 |   648 |   317 (10)| 00:00:01 |       |       |  Q1,01 | P->P | RANGE     |
|   6 |       HASH GROUP BY     |        |    72 |   648 |   317 (10)| 00:00:01 |       |       |  Q1,01 | PCWP |     |
|   7 |        PX RECEIVE     |        |    72 |   648 |   317 (10)| 00:00:01 |       |       |  Q1,01 | PCWP |     |
|   8 |  PX SEND HASH     | :TQ10000 |    72 |   648 |   317 (10)| 00:00:01 |       |       |  Q1,00 | P->P | HASH     |
|   9 |   HASH GROUP BY     |        |    72 |   648 |   317 (10)| 00:00:01 |       |       |  Q1,00 | PCWP |     |
|  10 |    PX BLOCK ITERATOR |        |   918K|  8075K|   292  (2)| 00:00:01 |     1 |    28 |  Q1,00 | PCWC |     |
|  11 |     TABLE ACCESS FULL| SALES    |   918K|  8075K|   292  (2)| 00:00:01 |     1 |    28 |  Q1,00 | PCWP |     |
-------------------------------------------------------------------------------------------------------------------------------------
Note
-----
   - automatic DOP: Computed Degree of Parallelism is 2

Statistics
----------------------------------------------------------
       2056  recursive calls
   0  db block gets
       4940  consistent gets
       1724  physical reads
   0  redo size
       2224  bytes sent via SQL*Net to client
 567  bytes received via SQL*Net from client
   6  SQL*Net roundtrips to/from client
 131  sorts (memory)
   0  sorts (disk)
  72  rows processed
SELECT /*+ parallel(8) */
 prod_id, SUM(amount_sold)
  FROM sales
 GROUP BY prod_id
  5   ORDER BY 2 DESC;

72 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 3876052276
-------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation      | Name     | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |    TQ |IN-OUT| PQ Distrib |
-------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |        |    72 |   648 |    80 (10)| 00:00:01 |       |       | |      |     |
|   1 |  PX COORDINATOR      |        |       |       |     |        |       |       | |      |     |
|   2 |   PX SEND QC (ORDER)     | :TQ10002 |    72 |   648 |    80 (10)| 00:00:01 |       |       |  Q1,02 | P->S | QC (ORDER) |
|   3 |    SORT ORDER BY     |        |    72 |   648 |    80 (10)| 00:00:01 |       |       |  Q1,02 | PCWP |     |
|   4 |     PX RECEIVE      |        |    72 |   648 |    80 (10)| 00:00:01 |       |       |  Q1,02 | PCWP |     |
|   5 |      PX SEND RANGE     | :TQ10001 |    72 |   648 |    80 (10)| 00:00:01 |       |       |  Q1,01 | P->P | RANGE     |
|   6 |       HASH GROUP BY     |        |    72 |   648 |    80 (10)| 00:00:01 |       |       |  Q1,01 | PCWP |     |
|   7 |        PX RECEIVE     |        |    72 |   648 |    80 (10)| 00:00:01 |       |       |  Q1,01 | PCWP |     |
|   8 |  PX SEND HASH     | :TQ10000 |    72 |   648 |    80 (10)| 00:00:01 |       |       |  Q1,00 | P->P | HASH     |
|   9 |   HASH GROUP BY     |        |    72 |   648 |    80 (10)| 00:00:01 |       |       |  Q1,00 | PCWP |     |
|  10 |    PX BLOCK ITERATOR |        |   918K|  8075K|    73  (2)| 00:00:01 |     1 |    28 |  Q1,00 | PCWC |     |
|  11 |     TABLE ACCESS FULL| SALES    |   918K|  8075K|    73  (2)| 00:00:01 |     1 |    28 |  Q1,00 | PCWP |     |
-------------------------------------------------------------------------------------------------------------------------------------
Note
-----
   - Degree of Parallelism is 8 because of hint

Statistics
----------------------------------------------------------
  73  recursive calls
   0  db block gets
       1667  consistent gets
       1619  physical reads
   0  redo size
       2224  bytes sent via SQL*Net to client
 567  bytes received via SQL*Net from client
   6  SQL*Net roundtrips to/from client
   9  sorts (memory)
   0  sorts (disk)
  72  rows processed
SELECT a.dfo_number,
       a.tq_id,
       a.server_type,
       MIN(a.num_rows),
       MAX(a.num_rows),
       COUNT(*)
  FROM v$pq_tqstat a
 GROUP BY a.dfo_number, a.tq_id, a.server_type
  9   ORDER BY a.dfo_number, a.tq_id, a.server_type
 10  ;
DFO_NUMBER TQ_ID SERVER_TYPE          MIN(A.NUM_ROWS) MAX(A.NUM_ROWS)  COUNT(*)
---------- ---------- ---------------------------------------- --------------- --------------- ----------
  1     0 Consumer          40      96  8
  1     0 Producer          69      72  8
  1     1 Consumer           8      10  8
  1     1 Producer           5      12  8
  1     1 Ranger          72      72  1
  1     2 Consumer          72      72  1
  1     2 Producer           8      10  8
7 rows selected.

5.通过检查v$px_session视图,我们可以实时得到系统上正在发生的并执行的视图,这个视图显示当前哪些并行子进程正在执行SQL,将v$px_session,v$session和v$sql3个视图关联,使我们能识别出当前正在使用并行处理的会话和SQL,以及看到想要的和真实的并行度。

WITH px_session AS
 (SELECT qcsid,     
         qcserial#,     
         MAX(degree) degree,      
         MAX(req_degree) req_degree,        
         COUNT(*) no_of_processes 
    FROM v$px_session p
   GROUP BY qcsid, qcserial#)
SELECT s.sid, s.username, degree, req_degree, no_of_processes, sql_text
  FROM v$session s
  JOIN px_session p
    ON (s.sid = p.qcsid AND s.serial# = p.qcserial#)
  JOIN v$sql SQL
 14      ON (sql.sql_id = s.sql_id);
       SID USERNAME         DEGREE REQ_DEGREE NO_OF_PROCESSES
---------- ------------------------------ ---------- ---------- ---------------
SQL_TEXT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 15 SH        0      36       36
SELECT /*+ parallel(36) */  prod_id, SUM(amount_sold) FROM sh.sales  GROUP BY prod_id  ORDER BY 2 DESC

6.V$SYSSTAT 视图包含一些与并行查询降级有关的统计数据,它可以帮助我们确定与请求并行度相比,并性查询被降级的频度

7.确保执行计划的所有部分都做了并行化,在一个复杂的并行sql中,确保查询执行中的所有重要步骤都实现了并行是很重要的,如果复杂查询中一个步骤以串行执行,其他的并行步骤可能必须等待串行步骤完成,从而将并行化的有点丢失,dbms_xplan中的S>P,

例如,在下面的实例中,CUSTOMERS表实现了并行,但SALE表没有,这个两个表联结和group by包括许多的并行化操作,但是sales表的全表扫描没有没有实现并行化,警告S->P标签显示SALES表的行以串行的方式传输到接下来的并行操作中。

SQL> alter table customers parallel(degree 4);
Table altered.
SQL> alter table sales noparallel;
Table altered.
explain plan for SELECT /* ordered use_hash(c) */
 cust_last_name, SUM(amount_sold)
  FROM sales s
  JOIN customers c
 USING (cust_id)
  6   GROUP BY cust_last_name;
Explained.
SQL> select * from table(dbms_xplan.display(null,null,'BASIC +PARALLEL'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3204180427
--------------------------------------------------------------------------------
| 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 GROUP BY       |    |  Q1,03 | PCWP |        |
|   4 |     PX RECEIVE        |    |  Q1,03 | PCWP |        |
|   5 |      PX SEND HASH       | :TQ10002  |  Q1,02 | P->P | HASH       |
|   6 |       HASH GROUP BY       |    |  Q1,02 | PCWP |        |
|   7 |        HASH JOIN       |    |  Q1,02 | PCWP |        |
|   8 |  PX RECEIVE       |    |  Q1,02 | PCWP |        |
|   9 |   PX SEND HASH       | :TQ10001  |  Q1,01 | P->P | HASH       |
|  10 |    PX BLOCK ITERATOR   |    |  Q1,01 | PCWC |        |
|  11 |     TABLE ACCESS FULL  | CUSTOMERS |  Q1,01 | PCWP |        |
|  12 |  BUFFER SORT       |    |  Q1,02 | PCWC |        |
|  13 |   PX RECEIVE       |    |  Q1,02 | PCWP |        |
|  14 |    PX SEND HASH       | :TQ10000  |    | S->P | HASH       |
|  15 |     PARTITION RANGE ALL|    |    |   |        |
|  16 |      TABLE ACCESS FULL | SALES   |    |   |        |
--------------------------------------------------------------------------------
23 rows selected.

一个部分并行的执行计划,例如前面提及的那个,可能提供了两种最坏的情况,因为串行的操作形成了对整体执行的瓶颈,耗时并没有得到提高,然而,sql占用了并行服务器进程,可能影响其他并行执行的sql的性能。如果我们设置了sales表的并行度,串行瓶颈将消失,sales表的全表扫描现在以并行方式执行,而且S->P的瓶颈替换成了完全并行化的P->P操作

SQL> alter table sales parallel(degree 4);
Table altered.
explain plan for SELECT /* ordered use_hash(c) */
 cust_last_name, SUM(amount_sold)
  FROM sales s
  JOIN customers c
 USING (cust_id)
  6   GROUP BY cust_last_name;
Explained.
SQL> select * from table(dbms_xplan.display(null,null,'BASIC +PARALLEL'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2890400653
------------------------------------------------------------------------------
| Id  | Operation      | Name |    TQ  |IN-OUT| PQ Distrib |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |  |  | |      |
|   1 |  PX COORDINATOR      |  |  | |      |
|   2 |   PX SEND QC (RANDOM)     | :TQ10002 |  Q1,02 | P->S | QC (RAND)  |
|   3 |    HASH GROUP BY     |  |  Q1,02 | PCWP |      |
|   4 |     PX RECEIVE      |  |  Q1,02 | PCWP |      |
|   5 |      PX SEND HASH     | :TQ10001 |  Q1,01 | P->P | HASH      |
|   6 |       HASH GROUP BY     |  |  Q1,01 | PCWP |      |
|   7 |        HASH JOIN     |  |  Q1,01 | PCWP |      |
|   8 |  PX RECEIVE     |  |  Q1,01 | PCWP |      |
|   9 |   PX SEND BROADCAST  | :TQ10000 |  Q1,00 | P->P | BROADCAST  |
|  10 |    PX BLOCK ITERATOR |  |  Q1,00 | PCWC |      |
|  11 |     TABLE ACCESS FULL| CUSTOMERS |  Q1,00 | PCWP |      |
|  12 |  PX BLOCK ITERATOR   |  |  Q1,01 | PCWC |      |
|  13 |   TABLE ACCESS FULL  | SALES |  Q1,01 | PCWP |      |
------------------------------------------------------------------------------
20 rows selected.

8.RAC的并行执行。在真正的应用集群(RAC)的数据库中,SQL可以在组成集群的多个实例上执行并行操作,除非采取了特定的步骤来阻止它,否则ORACLE在整个集群上无缝地执行并行操作。

 

SELECT a.dfo_number,
       a.tq_id,
       a.server_type,
       MIN(a.num_rows) min_rows,
       MAX(a.num_rows) max_rows,
       COUNT(*) dop,
       COUNT(DISTINCT instance) no_of_instances
  FROM v$pq_tqstat a
 GROUP BY a.dfo_number, a.tq_id, a.server_type
 10   ORDER BY a.dfo_number, a.tq_id, a.server_type DESC;
DFO_NUMBER TQ_ID SERVER_TYPE     MIN_ROWS   MAX_ROWS     DOP NO_OF_INSTANCES
---------- ---------- ---------------------------------------- ---------- ---------- ---------- ---------------
  1     0 Producer            26   70      30        1
  1     0 Consumer      0  125      30        1
  1     1 Ranger            72   72       1        1
  1     1 Producer      0    5      30        1
  1     1 Consumer      2   13      30        1
  1     2 Producer      2   13      30        1
  1     2 Consumer            72   72       1        1
7 rows selected.
Elapsed: 00:00:00.66

8.基于索引的并行查找,基于索引的查询通常是不能并行的,但是,如果涉及的索引是分区表上的本地分区索引,使用该索引的查找可以被并行处理。每个分区可由一个单独的进程运行,且可以实现与分区数量一样的高的并行度。

9.并行DML,任意一个运行扫描操作的DML语句都可以被并行,至少运行表读取那部分语句是可以的。

explain plan for update /*+ parallel(s) */
  2   sales set unit_price=amount_sold/quantity_sold;
Explained.
Elapsed: 00:00:01.23
SQL> select * from table(dbms_xplan.display(null,null,'BASIC +PARALLEL'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 83819421
-----------------------------------------------------------------------
| Id  | Operation       | Name  |    TQ  |IN-OUT| PQ Distrib |
-----------------------------------------------------------------------
|   0 | UPDATE STATEMENT      |   |   |  |       |
|   1 |  UPDATE        | SALES  |   |  |       |
|   2 |   PX COORDINATOR      |   |   |  |       |
|   3 |    PX SEND QC (RANDOM)| :TQ10000 |  Q1,00 | P->S | QC (RAND)  |
|   4 |     PX BLOCK ITERATOR |   |  Q1,00 | PCWC |       |
|   5 |      TABLE ACCESS FULL| SALES  |  Q1,00 | PCWP |       |
-----------------------------------------------------------------------
12 rows selected.
Elapsed: 00:00:00.15

SALES的全表扫描可以被并行处理,但请注意,尽管被更新的行可以被并行进程识别,真实的更新是由查询协调进程串行方式进行的,为了执行真正的并行DML,首先应该用下面的语句开启并行DML

SQL> alter session enable parallel DML;

为了是DML语句完全并行执行,发送一个alter session enable parallel DML的语句,否则,这个语句将只会部分被并行(最好的情况下)

10.并行插入:

INSERT /*+ parallel(s) */

INTO sales s

  SELECT /*+ parallel(u) */

   *

    FROM sales_update u;
SQL> select * from table(dbms_xplan.display(null,null,'BASIC +PARALLEL'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 3385836410
------------------------------------------------------------------------------
| Id  | Operation   | Name  |    TQ  |IN-OUT| PQ Distrib |
------------------------------------------------------------------------------
|   0 | INSERT STATEMENT  |  |  | |      |
|   1 |  LOAD TABLE CONVENTIONAL | SALES |  | |      |
|   2 |   PX COORDINATOR  |  |  | |      |
|   3 |    PX SEND QC (RANDOM)  | :TQ10000 |  Q1,00 | P->S | QC (RAND)  |
|   4 |     PX BLOCK ITERATOR  |  |  Q1,00 | PCWC |      |
|   5 |      TABLE ACCESS FULL  | SALES_UPDATE |  Q1,00 | PCWP |      |
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
------------------------------------------------------------------------------
12 rows selected.

 所以并行插入的正确写法:

1. alter session enable parallel dml;    
2. insert /*+ append parallel(a 4) */ select /*+ parallel(b 4) */ * from b;

oracle 10g 并行HINT如下写法,11不用添加表的名字

select /*+parallel(a,4),parallel(b,4),parallel(c,4),parallel(d,4),parallel(e,4)

*/ * from a,b,c,d,e

 11.DDL并行,

create index 和CREATE TABLE AS SELECT 这样的DDL语句都能做并行处理,create table as select  使用与并行插入极相似的方式处理并行。

explain plan for create index sales_idx
  2  on sales(prod_id,time_id) parallel(degree 8);
Explained.
SQL> select * from table(dbms_xplan.display(null,null,'BASIC +PARALLEL'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 967460003
---------------------------------------------------------------------------
| Id  | Operation   | Name      |   TQ  |IN-OUT| PQ Distrib |
---------------------------------------------------------------------------
|   0 | CREATE INDEX STATEMENT  |      |       |      |    |
|   1 |  PX COORDINATOR   |      |       |      |    |
|   2 |   PX SEND QC (ORDER)  | :TQ10001  | Q1,01 | P->S | QC (ORDER) |
|   3 |    INDEX BUILD NON UNIQUE| SALES_IDX | Q1,01 | PCWP |    |
|   4 |     SORT CREATE INDEX  |      | Q1,01 | PCWP |    |
|   5 |      PX RECEIVE   |      | Q1,01 | PCWP |    |
|   6 |       PX SEND RANGE  | :TQ10000  | Q1,00 | P->P | RANGE   |
|   7 |        PX BLOCK ITERATOR |      | Q1,00 | PCWC |    |
|   8 |  TABLE ACCESS FULL| SALES     | Q1,00 | PCWP |    |
---------------------------------------------------------------------------
15 rows selected.
explain plan for
create table sales_copy parallel(degree 8)
  3  as select * from sales;
Explained.
SQL> select * from table(dbms_xplan.display(null,null,'BASIC +PARALLEL'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1556691280
--------------------------------------------------------------------------
| Id  | Operation        | Name     |  TQ  |IN-OUT| PQ Distrib |
--------------------------------------------------------------------------
|   0 | CREATE TABLE STATEMENT |     |      |     |   |
|   1 |  PX COORDINATOR        |     |      |     |   |
|   2 |   PX SEND QC (RANDOM)  | :TQ10000   |  Q1,00 | P->S | QC (RAND)  |
|   3 |    LOAD AS SELECT      | SALES_COPY |  Q1,00 | PCWP |   |
|   4 |     PX BLOCK ITERATOR  |     |  Q1,00 | PCWC |   |
|   5 |      TABLE ACCESS FULL | SALES     |  Q1,00 | PCWP |   |
--------------------------------------------------------------------------
12 rows selected.

 

扩展:怎样避免数据仓库获取不到并行进程,而导致存储过程跑得慢:

BEGIN

  FOR i IN 1 .. 5 LOOP

    SELECT a.value

      INTO v_num

      FROM v$px_process_sysstat a

     WHERE a.statistic LIKE 'Servers Available%';

  END LOOP;

  IF v_num >= 8

  THEN

    dbms_output.put_line('足够进程');

    --执行JOB

  ELSE

    dbms_lock.sleep(60);

  END IF;

END;

你可能感兴趣的:(Oracle并行)