ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

Oracle 开发篇+管道函数性能测试

2021-03-05 15:04:10  阅读:128  来源: 互联网

标签:aa target price source 管道 stockpivot 测试 Oracle data


说明:本文为面向PL/SQL开发初学者的指导手册
标签:管道函数、管道表函数、表函数、管道、pipe
易学:文中删去了不需要的多余部分,让初学者一目了然一学就会
温馨提示:如果您发现本文哪里写的有问题或者有更好的写法请留言或私信我进行修改优化


★ 名词解释
表函数容许在SQL中调用PL/SQL的功能
管道函数又叫管道表函数也是一种表函数,它的运行特点是在函数运行期间“即时的”返回PL/SQL集合数据


★ 案例
SQL> INSERT INTO   tickertable (ticker, price_type, price, price_date)
            SELECT ticker, price_type, price, price_date
            FROM   TABLE(stockpivot_pkg.pipe_stocks(CURSOR(SELECT * FROM stocktable)));


★ 工作流程
*********************************
*                  ·····   *
*     SQL  管道函数  ·PL/SQL·   *
*                  ·····   *
*********************************


★ 相关文章
《Oracle PL/SQL程序设计 第6版》

★ 场景说明
从外部表(stocktable)中提取数据,然后插入数据库表(tickertable)中


★ 脚本说明
※ 环境准备:stockpivot_setup.sql
※ 执行方式:stockpivot_run.sql
※ 测试脚本:stockpivot_test.sql
※ 测试结果:stockpivot_test.txt
※ 清理脚本:stockpivot_teardown.sql


★ 测试内容
常规的PL/SQL
优化的PL/SQL
只用管道函数的PL/SQL
使用了bulck collect优化的管道函数的PL/SQL
使用了bulck collect+并行优化的管道函数的PL/SQL


★ 主要对象
※ load_stocks_legacy
  类型:存储过程
  功能:用来一条一条的执行常规的DML
  耗时:57.43 seconds
  redo:273,003K
※ load_stocks_forall
  类型:存储过程
  功能:用来测试Bukck+forall的性能
  耗时:5.07 seconds
  redo:37,918K
※ load_stocks
  类型:存储过程
  功能:用来调用普通的管道函数(pipe_stocks)
  耗时:16.47 seconds
  redo:37,559K
※ load_stocks_array
  类型:存储过程
  功能:用来调用使用了数组的管道函数(pipe_stocks_array)
  耗时:6.26 seconds
  redo:37,550K
※ load_stocks_parallel
  类型:存储过程
  功能:用来调用使用了并行+数组的管道函数(pipe_stocks_parallel)
  耗时:3.41 seconds
  redo:25K


★ 相关信息
※ 表
CREATE TABLE stocktable(外部表)
CREATE TABLE tickertable(堆表)
※ SQL数据类型
CREATE TYPE stockpivot_ot  AS OBJECT(对象类型)
CREATE TYPE stockpivot_ntt AS TABLE OF stockpivot_ot(集合)
※ PL/SQL数据类型
TYPE    stocktable_rct  IS REF CURSOR RETURN stocktable%ROWTYPE;(强类型的引用游标)
TYPE    stocktable_aat  IS TABLE OF stocktable%ROWTYPE INDEX BY PLS_INTEGER;(集合)
SUBTYPE stocktable_rt   IS stocktable%ROWTYPE;(游标)
TYPE    tickertable_aat IS TABLE OF tickertable%ROWTYPE INDEX BY PLS_INTEGER;(集合)
SUBTYPE tickertable_rt  IS tickertable%ROWTYPE;(游标)

 

★ 实验数据(stockpivot_setup.sql)

CREATE OR REPLACE DIRECTORY dir AS '/home/oracle';
grant read,write on directory dir to scott;
grant dba to scott;

DECLARE
   f UTL_FILE.FILE_TYPE := UTL_FILE.FOPEN('DIR', 'stocktable.dat', 'w');
BEGIN
   FOR r IN (WITH opening_prices AS (
                     SELECT 'STK' || TO_CHAR(ROWNUM) AS ticker
                     ,      ROUND(DBMS_RANDOM.VALUE(0, 2000), 4) AS open_price
                     ,      SYSDATE-ABS(DBMS_RANDOM.VALUE(0,30)) AS trade_date
                     FROM   dual
                     CONNECT BY ROWNUM <= &num_rows
                     )
             SELECT ticker 
             ,      open_price 
             ,      ROUND(open_price * ABS(DBMS_RANDOM.VALUE(0.1,2)),4) AS close_price
             ,      trade_date
             FROM   opening_prices)
   LOOP
      UTL_FILE.PUT_LINE(f, r.ticker || ',' || r.open_price || ',' || 
                           r.close_price || ',' || TO_CHAR(r.trade_date, 'DD/MM/YYYY'));
   END LOOP;
   UTL_FILE.FCLOSE(f);
END;
/

CREATE TABLE stocktable
( ticker      VARCHAR2(10)
, open_price  NUMBER
, close_price NUMBER 
, trade_date  DATE
)
ORGANIZATION EXTERNAL
(
  TYPE ORACLE_LOADER
  DEFAULT DIRECTORY dir
  ACCESS PARAMETERS
  (
     RECORDS DELIMITED by NEWLINE
     NOBADFILE
     NOLOGFILE
     NODISCARDFILE
     FIELDS TERMINATED BY ','
     ( ticker
     , open_price
     , close_price
     , trade_date CHAR(20) DATE_FORMAT DATE MASK "DD/MM/YYYY"
     )
  )
  LOCATION ('stocktable.dat')
)
REJECT LIMIT UNLIMITED;

exec DBMS_STATS.GATHER_TABLE_STATS(USER, 'STOCKTABLE', estimate_percent=>NULL);

CREATE TABLE tickertable
( ticker      VARCHAR2(10)
, price_type  VARCHAR2(1)
, price       NUMBER 
, price_date  DATE
);

CREATE TYPE stockpivot_ot AS OBJECT
( ticker      VARCHAR2(10)
, price_type  VARCHAR2(1)
, price       NUMBER 
, price_date  DATE
);
/

CREATE TYPE stockpivot_ntt AS TABLE OF stockpivot_ot;
/

CREATE PACKAGE stockpivot_pkg AS

   c_default_limit CONSTANT PLS_INTEGER := 100;

   TYPE stocktable_rct IS REF CURSOR
      RETURN stocktable%ROWTYPE;

   TYPE stocktable_aat IS TABLE OF stocktable%ROWTYPE
      INDEX BY PLS_INTEGER;

   SUBTYPE stocktable_rt IS stocktable%ROWTYPE;

   TYPE tickertable_aat IS TABLE OF tickertable%ROWTYPE
      INDEX BY PLS_INTEGER;

   SUBTYPE tickertable_rt IS tickertable%ROWTYPE;

   PROCEDURE load_stocks_legacy;

   PROCEDURE load_stocks_forall(
             p_limit_size  IN PLS_INTEGER DEFAULT stockpivot_pkg.c_default_limit
             );

   FUNCTION pipe_stocks( 
            p_source_data IN stockpivot_pkg.stocktable_rct 
            ) RETURN stockpivot_ntt PIPELINED;

   FUNCTION pipe_stocks_array( 
            p_source_data IN stockpivot_pkg.stocktable_rct,
            p_limit_size  IN PLS_INTEGER DEFAULT stockpivot_pkg.c_default_limit
            ) RETURN stockpivot_ntt PIPELINED;

   FUNCTION pipe_stocks_parallel( 
            p_source_data IN stockpivot_pkg.stocktable_rct,
            p_limit_size  IN PLS_INTEGER DEFAULT stockpivot_pkg.c_default_limit
            ) RETURN stockpivot_ntt 
              PIPELINED
              PARALLEL_ENABLE (PARTITION p_source_data BY ANY);

   PROCEDURE load_stocks;
   PROCEDURE load_stocks_array;
   PROCEDURE load_stocks_parallel;

END stockpivot_pkg;
/

CREATE PACKAGE BODY stockpivot_pkg AS

   -----------------------------------------------------------------------
   PROCEDURE load_stocks_legacy IS

      CURSOR c_source_data IS
         SELECT ticker, open_price, close_price, trade_date
         FROM   stocktable;

      r_source_data stockpivot_pkg.stocktable_rt;
      r_target_data stockpivot_pkg.tickertable_rt;

   BEGIN
      OPEN c_source_data;
      LOOP
         FETCH c_source_data INTO r_source_data;
         EXIT WHEN c_source_data%NOTFOUND;

         /* Opening price... */
         r_target_data.ticker      := r_source_data.ticker;
         r_target_data.price_type  := 'O';
         r_target_data.price       := r_source_data.open_price;
         r_target_data.price_date  := r_source_data.trade_date;
      
         INSERT INTO tickertable VALUES r_target_data;

         /* Closing price... */
         r_target_data.price_type := 'C';
         r_target_data.price      := r_source_data.close_price;
         
         INSERT INTO tickertable VALUES r_target_data;

      END LOOP;

      DBMS_OUTPUT.PUT_LINE( 
         c_source_data%ROWCOUNT * 2 || ' rows inserted.' );

      CLOSE c_source_data;
   END load_stocks_legacy;

   -----------------------------------------------------------------------
   FUNCTION pipe_stocks( 
            p_source_data IN stockpivot_pkg.stocktable_rct 
            ) RETURN stockpivot_ntt PIPELINED IS

      r_target_data stockpivot_ot := stockpivot_ot(NULL, NULL, NULL, NULL);
      r_source_data stockpivot_pkg.stocktable_rt;

   BEGIN
      LOOP
         FETCH p_source_data INTO r_source_data;
         EXIT WHEN p_source_data%NOTFOUND;

         /* First row... */
         r_target_data.ticker     := r_source_data.ticker;
         r_target_data.price_type := 'O';
         r_target_data.price      := r_source_data.open_price;
         r_target_data.price_date := r_source_data.trade_date;
         PIPE ROW (r_target_data);

         /* Second row... */
         r_target_data.price_type := 'C';
         r_target_data.price      := r_source_data.close_price;
         PIPE ROW (r_target_data);

      END LOOP;
      CLOSE p_source_data;
      RETURN;
   END pipe_stocks;

   -----------------------------------------------------------------------
   FUNCTION pipe_stocks_array( 
            p_source_data IN stockpivot_pkg.stocktable_rct,
            p_limit_size  IN PLS_INTEGER DEFAULT stockpivot_pkg.c_default_limit
            ) RETURN stockpivot_ntt PIPELINED IS

      r_target_data  stockpivot_ot := stockpivot_ot(NULL, NULL, NULL, NULL);
      aa_source_data stockpivot_pkg.stocktable_aat;

   BEGIN
      LOOP
         FETCH p_source_data BULK COLLECT INTO aa_source_data LIMIT p_limit_size;
         EXIT WHEN aa_source_data.COUNT = 0;

         /* Process the batch of (p_limit_size) records... */
         FOR i IN 1 .. aa_source_data.COUNT LOOP
   
            /* First row... */
            r_target_data.ticker     := aa_source_data(i).ticker;
            r_target_data.price_type := 'O';
            r_target_data.price      := aa_source_data(i).open_price;
            r_target_data.price_date := aa_source_data(i).trade_date;
            PIPE ROW (r_target_data);

            /* Second row... */
            r_target_data.price_type := 'C';
            r_target_data.price      := aa_source_data(i).close_price;
            PIPE ROW (r_target_data);

         END LOOP;

      END LOOP;
      CLOSE p_source_data; 
      RETURN;

   END pipe_stocks_array;

   -----------------------------------------------------------------------
   FUNCTION pipe_stocks_parallel( 
            p_source_data IN stockpivot_pkg.stocktable_rct,
            p_limit_size  IN PLS_INTEGER DEFAULT stockpivot_pkg.c_default_limit
            ) RETURN stockpivot_ntt 
              PIPELINED
              PARALLEL_ENABLE (PARTITION p_source_data BY ANY) IS

      r_target_data  stockpivot_ot := stockpivot_ot(NULL, NULL, NULL, NULL);
      aa_source_data stockpivot_pkg.stocktable_aat;

   BEGIN
      LOOP
         FETCH p_source_data BULK COLLECT INTO aa_source_data LIMIT p_limit_size;
         EXIT WHEN aa_source_data.COUNT = 0;

         /* Process the batch of (p_limit_size) records... */
         FOR i IN 1 .. aa_source_data.COUNT LOOP
   
            /* First row... */
            r_target_data.ticker     := aa_source_data(i).ticker;
            r_target_data.price_type := 'O';
            r_target_data.price      := aa_source_data(i).open_price;
            r_target_data.price_date := aa_source_data(i).trade_date;
            PIPE ROW (r_target_data);

            /* Second row... */
            r_target_data.price_type := 'C';
            r_target_data.price      := aa_source_data(i).close_price;
            PIPE ROW (r_target_data);

         END LOOP;

      END LOOP;
      CLOSE p_source_data; 
      RETURN;

   END pipe_stocks_parallel;

   -----------------------------------------------------------------------
   PROCEDURE load_stocks IS
   BEGIN

      INSERT INTO tickertable (ticker, price_type, price, price_date)
      SELECT ticker, price_type, price, price_date
      FROM   TABLE(
                stockpivot_pkg.pipe_stocks(
                   CURSOR(SELECT * FROM stocktable)));

      DBMS_OUTPUT.PUT_LINE( SQL%ROWCOUNT || ' rows inserted.' );

   END load_stocks;

   -----------------------------------------------------------------------
   PROCEDURE load_stocks_array IS
   BEGIN

      INSERT INTO tickertable (ticker, price_type, price, price_date)
      SELECT ticker, price_type, price, price_date
      FROM   TABLE(
                stockpivot_pkg.pipe_stocks_array(
                   CURSOR(SELECT * FROM stocktable)));

      DBMS_OUTPUT.PUT_LINE( SQL%ROWCOUNT || ' rows inserted.' );

   END load_stocks_array;

   -----------------------------------------------------------------------
   PROCEDURE load_stocks_parallel IS
   BEGIN

      EXECUTE IMMEDIATE 'ALTER SESSION ENABLE PARALLEL DML';

      INSERT /*+ PARALLEL(t, 4) */ INTO tickertable t
            (ticker, price_type, price, price_date)
      SELECT ticker, price_type, price, price_date
      FROM   TABLE(
                stockpivot_pkg.pipe_stocks_parallel(
                   CURSOR(SELECT /*+ PARALLEL(s, 4) */ * FROM stocktable s)));

      DBMS_OUTPUT.PUT_LINE( SQL%ROWCOUNT || ' rows inserted.' );

   END load_stocks_parallel;

   -----------------------------------------------------------------------
   PROCEDURE load_stocks_forall(
             p_limit_size  IN PLS_INTEGER DEFAULT stockpivot_pkg.c_default_limit
             ) IS

      CURSOR c_source_data IS
         SELECT ticker, open_price, close_price, trade_date
         FROM   stocktable;

      aa_source_data stockpivot_pkg.stocktable_aat;
      aa_target_data stockpivot_pkg.tickertable_aat;
      v_indx         PLS_INTEGER;
      v_rowcount     PLS_INTEGER := 0;

   BEGIN
      OPEN c_source_data;
      LOOP
         FETCH c_source_data BULK COLLECT INTO aa_source_data LIMIT p_limit_size;
         EXIT WHEN aa_source_data.COUNT = 0;

         aa_target_data.DELETE;

         FOR i IN 1 .. aa_source_data.COUNT LOOP

            /* Opening price... */
            v_indx := aa_target_data.COUNT + 1;
            aa_target_data(v_indx).ticker      := aa_source_data(i).ticker;
            aa_target_data(v_indx).price_type  := 'O';
            aa_target_data(v_indx).price       := aa_source_data(i).open_price;
            aa_target_data(v_indx).price_date  := aa_source_data(i).trade_date;
      
            /* Closing price... */
            v_indx := aa_target_data.COUNT + 1;
            aa_target_data(v_indx).ticker      := aa_source_data(i).ticker;
            aa_target_data(v_indx).price_type  := 'C';
            aa_target_data(v_indx).price       := aa_source_data(i).close_price;
            aa_target_data(v_indx).price_date  := aa_source_data(i).trade_date;
         
         END LOOP;

         FORALL i IN INDICES OF aa_target_data
            INSERT INTO tickertable 
            VALUES aa_target_data(i);

         v_rowcount := v_rowcount + SQL%ROWCOUNT;

      END LOOP;

      DBMS_OUTPUT.PUT_LINE( v_rowcount || ' rows inserted.' );

      CLOSE c_source_data;
   END load_stocks_forall;

END stockpivot_pkg;
/

 


※ 如果您觉得文章写的还不错, 别忘了在文末给作者点个赞哦 ~

over

标签:aa,target,price,source,管道,stockpivot,测试,Oracle,data
来源: https://blog.csdn.net/zzt_2009/article/details/114396792

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有