从pl / sql块返回数据行

时间:2014-09-26 21:04:05

标签: oracle plsql cursors bulk-collect

我想编写pl / sql代码,它利用Cursor和Bulk Collect来检索我的数据。我的数据库有大约数百万行,有时我必须查询它以获取客户端请求中的几乎所有记录。我分批进行查询和后续处理,以便不会使服务器拥塞并向客户端显示增量进度。我已经看到,为以后的批次挖掘需要花费更多的时间,这就是为什么我试图通过游标来实现它。

这是围绕我的主sql查询应该是简单的pl / sql:

declare
  cursor device_row_cur
    is
      select /my_query_details/;

  type  l_device_rows is table of device_row_cur%rowtype;
  out_entries l_device_rows := l_device_rows();

begin
    open device_row_cur;    
      fetch device_row_cur
      bulk collect into out_entries
      limit 100;        
  close device_row_cur; 
end;

我正在进行100批次,并将它们提取到out_entries。问题是这个块编译并执行得很好,但不会返回它所获取的数据行。我希望它以select的方式返回那些行。怎么能实现这一目标?有什么想法吗?

2 个答案:

答案 0 :(得分:3)

匿名阻止无法返回任何内容。您可以在块内为绑定变量赋值,包括集合类型或引用游标。但是必须在块之外定义和声明集合。也就是说,它必须是一个可以在纯SQL中使用的类型,而不是PL / SQL中定义的类型。目前你正在使用在块中定义的PL / SQL类型,以及在块内声明的变量 - 因此它超出了客户端的范围,并且在它之外也不是有效类型。 (它也不需要初始化,但这是一个小问题。)

根据它的实际消耗方式,一个选项是使用引用游标,您可以通过SQL * Plus或SQL Developer使用variableprint命令声明并显示它。例如:

variable rc sys_refcursor

begin
  open :rc for ( select ... /* your cursor statement */ );
end;
/

print rc

您可以从客户端应用程序执行类似操作,例如有一个函数返回一个引用游标或一个带有out参数的过程,该参数是一个引用游标,并从应用程序绑定它。然后迭代ref游标作为结果集。但细节取决于您的应用程序使用的语言。

另一种选择是使用一个流水线函数返回一个表类型 - 再次在SQL级别定义(使用create type)而不是在PL / SQL中 - 这可能比一次性返回的集合消耗更少的资源。

但我不得不质疑你为什么要这样做。你说“为以后的批次挖掘需要花费更多的时间”,这听起来像你在查询中使用分页机制,生成一个行号,然后在其中选择100的范围。如果您的客户端/应用程序想要获取所有行,那么单个查询执行会更简单,但按批次提取结果集。

不幸的是,如果没有关于应用程序的任何信息,这只是推测......

答案 1 :(得分:1)

我研究了这篇关于优化分页的优秀论文: http://www.inf.unideb.hu/~gabora/pagination/article/Gabor_Andras_pagination_article.pdf

我主要使用技术6。它描述了如何限制查询以获取页面x及以后的页面。为了进一步改进,您可以进一步限制它以单独获取页面x。如果使用得当,它可以使性能提高1000倍。

我没有返回自定义表行(这非常难,如果不是不可能与Java接口),我在pl / sql中打开了一个sys_refcursor,它可以是接口,例如:

OracleCallableStatement stmt = (OracleCallableStatement) connection.prepareCall(sql); stmt.registerOutParameter(someIndex, OracleTypes.CURSOR); stmt.execute(); resultSet = stmt.getCursor(idx);