zoukankan      html  css  js  c++  java
  • 初试PL/SQL并行编程

    -----------------------------Cryking原创------------------------------
    -----------------------转载请注明出处,谢谢!------------------------ 

    并行处理能大大提高数据的处理速度,它依赖于硬件资源、网络资源等环境.

    并行处理的硬件资源环境分为5大类:

    1.传统的单台计算机、单处理器、单内核的机器.(无法进行并行处理,但是并行程序还是可以运行的,此时就和普通程序一样了)

    2.单台计算机、单处理器、多内核的机器.(目前本人的测试环境,没钱买多处理器的快哭了)

    3.单台计算机、多处理器、多内核的机器.

    4.集群系统

    5.分布式系统

    PS:如何查看几个处理器、几核,常用的软件就是CPU-Z.

    本人的测试机器CPU:

    单CPU,双核心处理器

    下面开始,编写一个普通的管道函数(这里演示的就是管道函数的并行处理):

    CREATE OR REPLACE FUNCTION pipe_test
    (
      c_empno SYS_REFCURSOR
     ,p       VARCHAR2 DEFAULT ','
    ) RETURN EMP_element
      PIPELINED IS
      v_element VARCHAR2(1000);
    BEGIN
      FETCH c_empno
        INTO v_element;
      LOOP
        EXIT WHEN c_empno%NOTFOUND;
        PIPE ROW(substr(v_element, 0, instr(v_element, p) - 1));
        LOOP
          v_element := substr(v_element
                             ,instr(v_element, p) + 1
                             ,length(v_element) - instr(v_element, p) + 1);
          EXIT WHEN instr(v_element, p) = 0;
          PIPE ROW(substr(v_element, 0, instr(v_element, p) - 1));
        END LOOP;
        PIPE ROW(v_element);
        FETCH c_empno
          INTO v_element;
      END LOOP;
      RETURN;
    END pipe_test;



    注意需要先建立类型EMP_element,如下:

    CREATE OR REPLACE TYPE EMP_element as table of varchar2(100);

    然后我们建立一个并行处理的管道函数:

    CREATE OR REPLACE FUNCTION parallel_test
    (
      p_empno SYS_REFCURSOR
     ,p       VARCHAR2 DEFAULT ','
    ) RETURN EMP_element
      PIPELINED
      PARALLEL_ENABLE(PARTITION p_empno BY ANY) IS
      v_element VARCHAR2(1000);
    BEGIN
      FETCH p_empno
        INTO v_element;
      LOOP
        EXIT WHEN p_empno%NOTFOUND;
        PIPE ROW(substr(v_element, 0, instr(v_element, p) - 1));
        LOOP
          v_element := substr(v_element
                             ,instr(v_element, p) + 1
                             ,length(v_element) - instr(v_element, p) + 1);
          EXIT WHEN instr(v_element, p) = 0;
          PIPE ROW(substr(v_element, 0, instr(v_element, p) - 1));
        END LOOP;
        PIPE ROW(v_element);
        FETCH p_empno
          INTO v_element;
      END LOOP;
      RETURN;
    END parallel_test;


    留意下启用并行的关键字PARALLEL_ENABLE.

    接下来我们构造大表进行测试,根据v$pq_sesstat视图的结果,我们来判断数据库系统是否真的进行了并行处理.

    12:57:52 SYS@orcl> create table big_data as select 'Cc' a,'Dd' b from dual connect by level<1000000;
    
    
    表已创建。
    
    已用时间:  00: 00: 01.92
    12:59:00 SYS@orcl> select count(*) from big_data;
    
      COUNT(*)
    ----------
        999999
    
    已选择 1 行。
    
    已用时间:  00: 00: 00.31
    13:47:08 SYS@orcl> set autot trace exp stat
    --普通管道函数耗时40.48秒
    13:48:42 SYS@orcl> select SCOTT.pipe_test(CURSOR(SELECT a||','||b from big_data)) FROM DUAL;
    
    已选择 1 行。
    
    已用时间:  00: 00: 40.48
    
    执行计划
    ----------------------------------------------------------
    Plan hash value: 2452824241
    
    ------------------------------------------------------------------------------------------------
    | Id  | Operation                          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
    ------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                   |           |     1 |       |     2   (0)| 00:00:01 |
    |   1 |  VIEW                              |           |  8168 |   414K|    29   (0)| 00:00:01 |
    |   2 |   COLLECTION ITERATOR PICKLER FETCH| PIPE_TEST |  8168 |       |    29   (0)| 00:00:01 |
    |   3 |  FAST DUAL                         |           |     1 |       |     2   (0)| 00:00:01 |
    ------------------------------------------------------------------------------------------------
    
    Note
    -----
       - dynamic sampling used for this statement (level=2)
    
    
    统计信息
    ----------------------------------------------------------
        1000515  recursive calls
              0  db block gets
        1000325  consistent gets
           1548  physical reads
              0  redo size
        6027769  bytes sent via SQL*Net to client
           1214  bytes received via SQL*Net from client
             10  SQL*Net roundtrips to/from client
              7  sorts (memory)
              0  sorts (disk)
              1  rows processed
    
    13:53:24 SYS@orcl> alter system flush shared_pool;
    
    系统已更改。
    
    已用时间:  00: 00: 01.43
    --使用启用并行的管道函数,耗时40.32,与普通的管道函数耗时差不多
    --奇怪的是执行计划了多了一个BIG_DATA的全表扫描操作了
    13:53:26 SYS@orcl> select SCOTT.parallel_test(CURSOR(SELECT a||','||b from big_data)) FROM DUAL;
    
    已选择 1 行。
    
    已用时间:  00: 00: 40.32
    
    执行计划
    ----------------------------------------------------------
    Plan hash value: 1682567826
    
    ----------------------------------------------------------------------------------------------------
    
    | Id  | Operation                          | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
    
    ----------------------------------------------------------------------------------------------------
    
    |   0 | SELECT STATEMENT                   |               |     1 |       |     2   (0)| 00:00:01 |
    
    |   1 |  VIEW                              |               |  8168 |   414K|    29   (0)| 00:00:01 |
    
    |   2 |   COLLECTION ITERATOR PICKLER FETCH| PARALLEL_TEST |  8168 |       |    29   (0)| 00:00:01 |
    
    |   3 |    TABLE ACCESS FULL               | BIG_DATA      |   968K|  7565K|   422   (3)| 00:00:06 |
    
    |   4 |  FAST DUAL                         |               |     1 |       |     2   (0)| 00:00:01 |
    
    ----------------------------------------------------------------------------------------------------
    
    
    Note
    -----
       - dynamic sampling used for this statement (level=2)
    
    
    统计信息
    ----------------------------------------------------------
        1000867  recursive calls
              0  db block gets
        1000353  consistent gets
           1560  physical reads
              0  redo size
        6026847  bytes sent via SQL*Net to client
           1006  bytes received via SQL*Net from client
              8  SQL*Net roundtrips to/from client
              9  sorts (memory)
              0  sorts (disk)
              1  rows processed
    --通过v$pq_sesstat视图我们发现此时系统并没有进行并行处理,(其实通过执行计划也可看出没有使用并行)
    13:54:21 SYS@orcl> select * from v$pq_sesstat;
    
    STATISTIC                      LAST_QUERY SESSION_TOTAL
    ------------------------------ ---------- -------------
    Queries Parallelized                    0             0
    DML Parallelized                        0             0
    DDL Parallelized                        0             0
    DFO Trees                               0             0
    Server Threads                          0             0
    Allocation Height                       0             0
    Allocation Width                        0             0
    Local Msgs Sent                         0             0
    Distr Msgs Sent                         0             0
    Local Msgs Recv'd                       0             0
    Distr Msgs Recv'd                       0             0
    
    已选择11行。
    
    已用时间:  00: 00: 00.00
    		  
    13:54:40 SYS@orcl> alter system flush buffer_cache;
    
    系统已更改。
    
    已用时间:  00: 00: 00.00
    13:55:27 SYS@orcl> alter system flush shared_pool;
    
    系统已更改。
    
    已用时间:  00: 00: 01.40
    --接下来我们加HINT,强制并行处理,此时耗时25.03秒,降低了一半
    13:55:30 SYS@orcl> select /*+ parallel */scott.PARALLEL_TEST(CURSOR(SELECT a||','||b from big_data))
     FROM DUAL;
    
    已选择 1 行。
    
    已用时间:  00: 00: 25.03
    
    执行计划
    ----------------------------------------------------------
    Plan hash value: 3127237831
    
    -----------------------------------------------------------------------------------------------------------------------------------
    
    | Id  | Operation                            | Name          | Rows  | Bytes | Cost (%CPU)| Time |    TQ  |IN-OUT| PQ Distrib |
    
    -----------------------------------------------------------------------------------------------------------------------------------
    
    |   0 | SELECT STATEMENT                     |               |     1 |       |     2   (0)| 00:00:01 |        |      |            |
    
    |   1 |  PX COORDINATOR                      |               |       |       |            | |        |      |            |
    
    |   2 |   PX SEND QC (RANDOM)                | :TQ10000      |  8168 |   414K|    16   (0)| 00:00:01 |  Q1,00 | P->S | QC (RAND)  |
    
    |   3 |    VIEW                              |               |  8168 |   414K|    16   (0)| 00:00:01 |  Q1,00 | PCWP |            |
    
    |   4 |     COLLECTION ITERATOR PICKLER FETCH| PARALLEL_TEST |  8168 |       |    16   (0)| 00:00:01 |  Q1,00 | PCWP |            |
    
    |   5 |      PX BLOCK ITERATOR               |               |   968K|  7565K|   234   (3)| 00:00:03 |  Q1,00 | PCWC |            |
    
    |   6 |       TABLE ACCESS FULL              | BIG_DATA      |   968K|  7565K|   234   (3)| 00:00:03 |  Q1,00 | PCWP |            |
    
    |   7 |  FAST DUAL                           |               |     1 |       |     2   (0)| 00:00:01 |        |      |            |
    
    -----------------------------------------------------------------------------------------------------------------------------------
    
    
    Note
    -----
       - dynamic sampling used for this statement (level=2)
       - automatic DOP: Computed Degree of Parallelism is 2
    
    
    统计信息
    ----------------------------------------------------------
        1000941  recursive calls
              4  db block gets
        1000516  consistent gets
           1842  physical reads
              0  redo size
        6026847  bytes sent via SQL*Net to client
           1006  bytes received via SQL*Net from client
              8  SQL*Net roundtrips to/from client
              9  sorts (memory)
              0  sorts (disk)
              1  rows processed
    --上面的执行计划及v$pq_sesstat都显示系统启用了并行处理,并行度为2
    13:57:44 SYS@orcl> select * from v$pq_sesstat;
    
    STATISTIC                      LAST_QUERY SESSION_TOTAL
    ------------------------------ ---------- -------------
    Queries Parallelized                    0             1
    DML Parallelized                        0             0
    DDL Parallelized                        0             0
    DFO Trees                               0             1
    Server Threads                          0             0
    Allocation Height                       0             0
    Allocation Width                        0             0
    Local Msgs Sent                         0           553
    Distr Msgs Sent                         0             0
    Local Msgs Recv'd                       0           553
    Distr Msgs Recv'd                       0             0
    
    已选择11行。
    
    已用时间:  00: 00: 00.01

    为了使示例更加有说服力,我们再来试一下普通管道函数+HINT强制并行看看:

    16:02:36 SYS@orcl> select /*+ parallel */SCOTT.pipe_test(CURSOR(SELECT a||','||b from big_data)) FROM DUAL;
    
    已选择 1 行。
    
    已用时间:  00: 00: 43.34
    
    执行计划
    ----------------------------------------------------------
    Plan hash value: 2452824241
    
    ------------------------------------------------------------------------------------------------
    | Id  | Operation                          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
    ------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                   |           |     1 |       |     2   (0)| 00:00:01 |
    |   1 |  VIEW                              |           |  8168 |   414K|    16   (0)| 00:00:01 |
    |   2 |   COLLECTION ITERATOR PICKLER FETCH| PIPE_TEST |  8168 |       |    16   (0)| 00:00:01 |
    |   3 |  FAST DUAL                         |           |     1 |       |     2   (0)| 00:00:01 |
    ------------------------------------------------------------------------------------------------
    
    Note
    -----
       - dynamic sampling used for this statement (level=2)
       - automatic DOP: Computed Degree of Parallelism is 1
    
    
    统计信息
    ----------------------------------------------------------
        1003093  recursive calls
             18  db block gets
        1000973  consistent gets
           1628  physical reads
              0  redo size
        6026843  bytes sent via SQL*Net to client
           1006  bytes received via SQL*Net from client
              8  SQL*Net roundtrips to/from client
            100  sorts (memory)
              0  sorts (disk)
              1  rows processed
    

    由于普通函数不支持并行,所以即使+HINT强制并行,系统还是没有使用并行处理.耗时依然为40多秒.

    如果不使用函数,使用普通的SQL,又是可以使用HINT强制并行的,如下:

    15:59:07 SYS@orcl> select /*+ parallel */ a||','||b from big_data;
    
    已选择999999行。
    
    已用时间:  00: 00: 04.09
    
    执行计划
    ----------------------------------------------------------
    Plan hash value: 2638980575
    
    --------------------------------------------------------------------------------------------------------------
    | Id  | Operation            | Name     | Rows  | Bytes | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
    --------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT     |          |   968K|  7565K|   234   (3)| 00:00:03 |        |      |         |
    |   1 |  PX COORDINATOR      |          |       |       |            |          |        |      |         |
    |   2 |   PX SEND QC (RANDOM)| :TQ10000 |   968K|  7565K|   234   (3)| 00:00:03 |  Q1,00 | P->S | QC (RAND)  |
    |   3 |    PX BLOCK ITERATOR |          |   968K|  7565K|   234   (3)| 00:00:03 |  Q1,00 | PCWC |         |
    |   4 |     TABLE ACCESS FULL| BIG_DATA |   968K|  7565K|   234   (3)| 00:00:03 |  Q1,00 | PCWP |         |
    --------------------------------------------------------------------------------------------------------------
    
    Note
    -----
       - dynamic sampling used for this statement (level=2)
       - automatic DOP: Computed Degree of Parallelism is 2
    
    
    统计信息
    ----------------------------------------------------------
              6  recursive calls
              0  db block gets
           1577  consistent gets
           1520  physical reads
              0  redo size
       13467035  bytes sent via SQL*Net to client
         733742  bytes received via SQL*Net from client
          66668  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
         999999  rows processed
    





    通过上面的示例可以看到,并行处理可以大大加速数据的处理,几乎成倍的提升性能.

    但并不是并行度为几,就会提示几倍的性能,它受硬件环境,优化器内部算法,PL/SQL引擎解析等等的约束.

    总之,并行处理给我们带来的性能提升是很大的,所以在某些场景使用并行编程也是很必要的.

  • 相关阅读:
    疯狂学java的第32天
    疯狂学java的第31天
    疯狂学java的第30天
    疯狂学java的第29天
    疯狂学java的第28天
    javaSE_day14_抽象类
    javaSE_day13_继承、super、this
    JavaSE_day12_static关键字丶单列设计模式丶代码块
    JavaSE_day11_常用类(String类丶StringBuffer类丶StringBuilder类)
    JavaSE_day10_初识API丶常用类(Scanner丶Random丶ArrayList)
  • 原文地址:https://www.cnblogs.com/snake-hand/p/3159640.html
Copyright © 2011-2022 走看看