Oracle:返回过程中带有光标的大型数据集

Oracle:返回过程中带有光标的大型数据集,oracle,performance,plsql,oracle-sqldeveloper,Oracle,Performance,Plsql,Oracle Sqldeveloper,我看过很多关于在PL/SQL中使用游标将数据返回给调用应用程序的帖子,但是没有一篇涉及到我认为我使用这种技术存在的问题。我对Oracle相当陌生,但对MSSQL Server有丰富的经验。在SQL Server中,当构建应用程序调用的查询以返回数据时,我通常将SELECT语句放在带有/不带参数的存储过程中,并让存储过程执行语句并自动返回数据。我了解到,使用PL/SQL,必须将结果数据集存储在游标中,然后使用游标 我们有一个查询,它不一定返回大量的行(~5K-10K行),但是数据集非常宽,因为它由

我看过很多关于在PL/SQL中使用游标将数据返回给调用应用程序的帖子,但是没有一篇涉及到我认为我使用这种技术存在的问题。我对Oracle相当陌生,但对MSSQL Server有丰富的经验。在SQL Server中,当构建应用程序调用的查询以返回数据时,我通常将SELECT语句放在带有/不带参数的存储过程中,并让存储过程执行语句并自动返回数据。我了解到,使用PL/SQL,必须将结果数据集存储在游标中,然后使用游标

我们有一个查询,它不一定返回大量的行(~5K-10K行),但是数据集非常宽,因为它由1400多列组成。在SQL Developer中运行SQL查询本身会立即返回结果。但是,调用为同一查询打开游标的过程需要5分钟以上的时间才能完成

创建或替换过程PROCNAME(结果输出系统\u REFCURSOR)
作为
开始
公开结果
...
结束;
在进行了一些调试以试图找到速度缓慢的根本原因之后,我倾向于光标,一次返回一行,速度非常慢。通过将proc代码转换成PL/SQL块并在SELECT查询后使用
DBMS\u SQL.return\u result(RESULTS)
,我可以实时看到这一点。运行此命令时,我可以在SQL Developer的“脚本输出”窗口中看到每一行,一次显示一行。如果这正是游标将数据返回给调用应用程序的方式,那么我完全可以看出这是一个瓶颈,因为返回所有5K-10K行可能需要5-10分钟。如果我从SELECT查询中删除列,光标显示所有行的速度会快得多,因此使用光标确实会出现大量列的问题

知道运行SQL查询本身会返回即时结果,我如何从游标中获得相同的性能?这似乎不可能。在这种情况下,答案是将嵌入式SQL放在应用程序代码中,而不是使用过程/游标返回数据吗?我们正在我们的环境中使用Oracle 12c

编辑:只想说明我是如何使用常规SELECT查询和PL/SQL块与游标方法测试性能的:

选择(需要约27秒才能返回约6K行):

选择
从…起
带游标的PL/SQL(返回约6K行需要约5-10分钟):

DECLARE RESULTS SYS\u REFCURSOR;
开始
公开结果
挑选
从…起
返回结果(RESULTS);
结束;

一些注释引用了在返回所有数据后控制台应用程序中发生的情况,但我只讨论了Oracle\SQL Developer中上述两种方法的性能。希望这有助于澄清我试图表达的观点。

您可以为SQL的两次执行运行SQL监视器报告;这会告诉你时间的确切位置。我还将考虑在两个快照间隔中运行这两种方法,并检查来自AWR差异报告和ADDM比较报告的输出;您可能会对这些比较报告提供的惊人细节感到惊讶。
此外,根据Oracle的说法,即使表中>255列是“否”,因为它会在>1个数据库块之间分割记录,从而增加检索结果所需的IO时间,但我怀疑您看到的两种方法之间的差异并不是IO问题,因为在直行SQL中,您报告的是快速结果获取。因此,我怀疑更多的是内存问题。您可能知道,PL/SQL代码将使用程序全局区域(PGA),因此我将检查参数PGA_aggregate_target,并将其增加到5GB(只是猜测)。在代码运行的时间间隔内运行ADDM报告将告诉您advisor是否建议更改该参数

每个SELECT语句都通过游标(隐式)进行处理。您是否尝试过Oracle管道函数?您能否显示您对游标(或它返回的数据)的具体操作?事实上,运行纯SQL语句和打开同一查询的游标应该没有区别。@TurtlesAllTheWayDown-没有听说过“pipelined”函数,但现在将检查它。@GuillermoGarcia,正如我已经提到的,对于同一查询,运行SQL查询和在PL/SQL块内打开游标没有区别。此外,打开光标对性能几乎没有影响。一旦您开始读取数据,数据库就开始为您的查询提供服务。所以,我猜,性能问题在某个侧面。如果没有额外的细节,很难准确地说出它是什么。“使用SQL语句,返回所有行(5K+),而不仅仅是默认的50行,需要27秒。通过过程/游标返回需要5+分钟”这听起来像是消耗游标的代码有问题。这与您在此处发布的存储过程无关。请发布从光标读取(获取)行的代码,也许有人可以帮助您。