我想编写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的方式返回那些行。怎么能实现这一目标?有什么想法吗?
答案 0 :(得分:3)
匿名阻止无法返回任何内容。您可以在块内为绑定变量赋值,包括集合类型或引用游标。但是必须在块之外定义和声明集合。也就是说,它必须是一个可以在纯SQL中使用的类型,而不是PL / SQL中定义的类型。目前你正在使用在块中定义的PL / SQL类型,以及在块内声明的变量 - 因此它超出了客户端的范围,并且在它之外也不是有效类型。 (它也不需要初始化,但这是一个小问题。)
根据它的实际消耗方式,一个选项是使用引用游标,您可以通过SQL * Plus或SQL Developer使用variable
和print
命令声明并显示它。例如:
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);