从Oracle 8开始,我们就可以从一个collection类型的数据集合中查询出数据,这个集合称之为“虚拟表“。它的方法是“SELECT FROM TABLE(CAST(plsql_function AS collection_type))”,据说该方法在处理大数据量时会有内存方面的限制。到了Oracle 9i之后,一个称为pipelined表函数的技术被推出来。他和普通的表函数很类似,但还有有一些显著的差别。

第一,pipelined函数处理的数据,是以管道的方式,或者说是流的方式从预先准备的小数组中展现给用户,而普通表函数将数据全部准备好再展现给用户。

第二,pipelined函数可以并发,这意味着PLSQL可以同一时间在多个进程上执行。

第三,pipelined函数可以很容易将存储过程转换成用bulk操作的行,有利于实现的复杂转换逻辑的SQL。

(miki西游 @mikixiyou 原文链接: http://mikixiyou.iteye.com/blog/1628397 )

了解pipelined函数的最佳方法是看一个简单的例子。对于任何一个pipelined函数,都必须有两点要求。

1、一个定义在模式中或者包中collection类型;

2、一个单独的PL/SQL函数或一个包中的函数,函数的返回类型后面必须加pipelined关键字;





在下面的例子中,我们将创建一个简单的pipelined函数,输出若干行记录。首先需要一个collection类型,用于格式化输出。

  1. CREATE OR REPLACE TYPE number_ntt AS TABLE OF NUMBER;

Oracle会使用这个类型缓存少量的记录作为pipelined函数调用时的输出。我们创建一个简单的pipelined函数。

  1. CREATE OR REPLACE FUNCTION row_generator(rows_in IN PLS_INTEGER)
  2. RETURN number_ntt  PIPELINED
  3. IS
  4. BEGIN
  5. FOR i IN 1 .. rows_in LOOP
  6. PIPE ROW(i);
  7. END LOOP;
  8. RETURN;
  9. END;

在这个SQL中:

在函数定义部分的关键字pipelined是pipelined函数定义的关键,返回的类型必须是事先定义的collection类型,如这里是number_tt。

在函数主体部分的”PIPE ROW”是将一个单行记录写入到collection流中。记录中所有字段的类型必须和collection类型中所有字段匹配。

在函数主体部分的“return“的值是一个空值,而不是有任何符合collection类的值。

这些就是pipelined函数定义时需要严格遵守的规则。

现在已经创建好一个pipelined函数,我们可以测试一下。

  1. SQL> select * from TABLE( row_generator(10) );
  2. COLUMN_VALUE
  3. ------------
  4. 1
  5. 2
  6. 3
  7. 4
  8. 5
  9. 6
  10. 7
  11. 8
  12. 9
  13. 10
  14. 10 rows selected

将pipelined函数row_generator放到一个“TABLE”操作符中,虚拟成一个数据源,类似表或视图。这里虚拟表只有一个字段,名称“COLUMN_VALUE“是其默认值。更复杂的输出则需要将collection定义得更复杂些,使用到object或者record。

我们通过一个例子比较一下pipelined函数或普通的表函数在返回collection时有何差异。

第一步,创建普通的表函数,返回colletion类型。

  1. CREATE OR REPLACE FUNCTION table_function RETURN number_ntt AS
  2. nt number_ntt := number_ntt();
  3. BEGIN
  4. FOR i IN 1 .. 500000 LOOP
  5. if (mod(i, 10000) = 0) then
  6. nt.EXTEND;
  7. nt(nt.LAST) := i;
  8. end if;
  9. END LOOP;
  10. RETURN nt; --<-- return whole collection
  11. END table_function;

第二步,创建pipelined函数,返回的也是collection类型

  1. CREATE OR REPLACE FUNCTION pipelined_function RETURN number_ntt
  2. PIPELINED AS
  3. BEGIN
  4. FOR i IN 1 .. 500000 LOOP
  5. if (mod(i, 10000) = 0) then
  6. PIPE ROW(i); --<-- send row to consumer
  7. end if;
  8. END LOOP;
  9. RETURN;
  10. END pipelined_function;

函数的功能都是将能和1000整除的数字输出出来。

再创建一个输出时间到毫秒的函数,用于测试两个函数的输出特点。

  1. CREATE FUNCTION get_time RETURN TIMESTAMP IS
  2. BEGIN
  3. RETURN LOCALTIMESTAMP;
  4. END get_time;
  5. /

第三步,测试两个函数

测试普通函数如下:

  1. ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'HH24:MI:SS.FF3';
  2. SELECT get_time() AS ts FROM DUAL;
  3. SELECT column_value, get_time() AS ts FROM TABLE(table_function);
  4. SQL>
  5. TS
  6. --------------------------------------------------------------------------------
  7. 15:27:26.031
  8. COLUMN_VALUE TS
  9. ------------ --------------------------------------------------------------------------------
  10. 100000 15:27:26.218
  11. 200000 15:27:26.218
  12. 300000 15:27:26.218
  13. 400000 15:27:26.218
  14. 500000 15:27:26.218
  15. SQL>

结果显示,所有记录都是同一时间输出。

测试pipelined函数如下:

  1. SELECT get_time() AS ts FROM DUAL;
  2. SELECT column_value, get_time() AS ts FROM TABLE(pipelined_function);
  3. TS
  4. --------------------------------------------------------------------------------
  5. 15:27:26.265
  6. COLUMN_VALUE TS
  7. ------------ --------------------------------------------------------------------------------
  8. 100000 15:27:26.312
  9. 200000 15:27:26.343
  10. 300000 15:27:26.390
  11. 400000 15:27:26.421
  12. 500000 15:27:26.453

结果显示,所有记录都是逐次输出。

这点对于用户的UI太重要了。试想,如果执行一个查询,过了10秒钟才显示出所有的结果好,还是还是每秒都显示一些记录,知道10秒钟显示完毕好?



如果这个输出的结果集再放到到百万记录,两个函数对PGA内存的消耗又完全不一样,这点更重要。

Oracle的pipelined函数实现高性能大数据处理的更多相关文章

  1. 翻译-In-Stream Big Data Processing 流式大数据处理

    相当长一段时间以来,大数据社区已经普遍认识到了批量数据处理的不足.很多应用都对实时查询和流式处理产生了迫切需求.最近几年,在这个理念的推动下,催生出了一系列解决方案,Twitter Storm,Yah ...

  2. [转载] 一共81个,开源大数据处理工具汇总(下),包括日志收集系统/集群管理/RPC等

    原文: http://www.36dsj.com/archives/25042 接上一部分:一共81个,开源大数据处理工具汇总(上),第二部分主要收集整理的内容主要有日志收集系统.消息系统.分布式服务 ...

  3. 一共81个,开源大数据处理工具汇总(下),包括日志收集系统/集群管理/RPC等

    作者:大数据女神-诺蓝(微信公号:dashujunvshen).本文是36大数据专稿,转载必须标明来源36大数据. 接上一部分:一共81个,开源大数据处理工具汇总(上),第二部分主要收集整理的内容主要 ...

  4. oracle的sql函数

    只读事务set transaction read only当一个用户添加了只读事务,则查询时只会查到设置只读事务之前的内容,在并发量大的系统中,通过设置只读事务 便于统计 oracle的sql函数的使 ...

  5. [转]ORACLE日期时间函数大全

    本文转自:http://www.cnblogs.com/chuncn/archive/2009/04/29/1381282.html ORACLE日期时间函数大全 TO_DATE格式(以时间: ::2 ...

  6. Spark大数据处理技术

    全球首部全面介绍Spark及Spark生态圈相关技术的技术书籍 俯览未来大局,不失精细剖析,呈现一个现代大数据框架的架构原理和实现细节 透彻讲解Spark原理和架构,以及部署模式.调度框架.存储管理及 ...

  7. oracle的nvl函数的使用解析

    Oracle的Nvl函数 nvl( ) 函数 从两个表达式返回一个非null 值. 语法 NVL(eExpression1, eExpression2) 参数 eExpression1, eExpre ...

  8. Oracle/Mysql/SqlServer函数区别

    mysql日期和时间格式转换 Linux scp 使用详解 Oracle/Mysql/SqlServer函数区别 2011-07-01 12:34:36|  分类: Mysql技术 |  标签:mys ...

  9. 0基础搭建Hadoop大数据处理-初识

    在互联网的世界中数据都是以TB.PB的数量级来增加的,特别是像BAT光每天的日志文件一个盘都不够,更何况是还要基于这些数据进行分析挖掘,更甚者还要实时进行数据分析,学习,如双十一淘宝的交易量的实时展示 ...

随机推荐

  1. c语言学习笔记 break语句

    比如 for() { for() { break; } } 那个break语句只是跳出它所在的那个for循环,不会把最外面的for循环都跳出去.

  2. 嵌入式Qt开发环境的搭建详解

    一.嵌入式Qt开发环境的搭建前奏 1.下载arm-linux-gcc-4.4.3-20100728.tar.gz 2.下载qt-everywhere-opensource-src-4.8.5.tar. ...

  3. UOJ 176 新年的繁荣

    挺妙的解法. 发现边权很小,我们可以考虑从大到小枚举边权来进行$kruskal$算法,这样子对于每一个边权$i$,我们只要枚举$0 \leq j < m$,找到一个点使它的点权为$i | 2^j ...

  4. Jackson-将对象转为Json字符串

    SpringMVC-处理JSON 1.引入jackson依赖 <properties> <jackson.version>1.9.13</jackson.version& ...

  5. JavaScript必备:Google发布的JS代码规范(转)

    [翻译]关于Google发布的JS代码规范,你需要了解什么? 翻译 | WhiteYin 译文 | https://github.com/WhiteYin/translation/issues/10 ...

  6. Spring:配置文件

    首先是bean.xml,配置所有的bean,一般也叫applicationContext.xml,应用程序上下文.示例: <?xml version="1.0" encodi ...

  7. Android 画个电池出来(Paint和canvas)

    1.Android中很多时候都要自己去画一个自定义控件出来,就需要用到Paint和Canvas这两个类. 2.效果图:

  8. 【大数据之数据仓库】GreenPlum优化器对比测试

    在< [大数据之数据仓库]选型流水记>一文中有提及,当时没有测试GreenPlum的quicklz压缩算法和ORCA查询优化器,考虑到quicklz压缩算法因为版权问题不会开源(详情请参阅 ...

  9. Struts2学习第2天--Struts2的Servlet的API的访问 Struts2的结果页面的配置 Struts2的数据的封装(包括复杂类型)

    启动后访问jsp 输入姓名密码: 提交后跳转打action 打印: 修改类: 配置同上 结果同上. 实现这俩接口 就得到了 以上代码附上: struts.xml: <?xml version=& ...

  10. lower_bound下确界

    //lower_bound用于找到首个大于等于某个值的元素 #include<algorithm> #include<iostream> using namespace std ...