【发布时间】:2020-07-07 12:51:56
【问题描述】:
我看过很多关于在 PL/SQL 中使用游标将数据返回给调用应用程序的帖子,但没有一篇涉及我认为我在使用这种技术时遇到的问题。我对 Oracle 还很陌生,但对 MSSQL Server 有丰富的经验。在 SQL Server 中,当构建由应用程序调用以返回数据的查询时,我通常将 SELECT 语句放在带/不带参数的存储过程中,并让存储过程执行语句并自动返回数据。我了解到,使用 PL/SQL,您必须将生成的数据集存储在游标中,然后使用游标。
我们的查询不一定会返回大量行(约 5K - 10K 行),但是数据集非常宽,因为它由 1400 多列组成。在 SQL Developer 中运行 SQL 查询本身会立即返回结果。但是,调用为相同查询打开游标的过程需要 5 分钟以上才能完成。
CREATE OR REPLACE PROCEDURE PROCNAME(RESULTS OUT SYS_REFCURSOR)
AS
BEGIN
OPEN RESULTS FOR
<SELECT_query_with_1400+_columns>
...
END;
在进行了一些调试以试图找到缓慢的根本原因后,我倾向于非常缓慢地一次返回一行的光标。实际上,我可以通过将 proc 代码转换为 PL/SQL 块并在 SELECT 查询后使用 DBMS_SQL.return_result(RESULTS) 来实时查看。运行此程序时,我可以在 SQL Developer 的脚本输出窗口中看到每一行一次显示一个。如果这正是游标将数据返回给调用应用程序的方式,那么我绝对可以看到这是瓶颈,因为完成返回所有 5K-10K 行可能需要 5-10 分钟。如果我从 SELECT 查询中删除列,游标会更快地显示所有行,因此使用游标似乎确实存在大量列的问题。
知道运行 SQL 查询本身会返回即时结果,我如何才能从游标中获得同样的性能?这似乎是不可能的。答案是将嵌入式 SQL 放在应用程序代码中,而不是在这种情况下使用过程/游标返回数据?我们在我们的环境中使用 Oracle 12c。
编辑:只是想说明我是如何使用常规 SELECT 查询与带有游标方法的 PL/SQL 块测试性能的:
SELECT(需要约 27 秒才能返回约 6K 行):
SELECT <1400+_columns>
FROM <table_name>;
带有游标的 PL/SQL(需要大约 5-10 分钟才能返回大约 6K 行):
DECLARE RESULTS SYS_REFCURSOR;
BEGIN
OPEN RESULTS FOR
SELECT <1400+_columns>
FROM <table_name>;
DBMS_SQL.return_result(RESULTS);
END;
一些 cmets 引用了所有数据返回后控制台应用程序中发生的情况,但我只谈论 Oracle\SQL Developer 中上述两种方法的性能。希望这有助于澄清我试图传达的观点。
【问题讨论】:
-
每个 SELECT 语句都通过游标(隐式)处理。您是否尝试过 Oracle 流水线功能?
-
你能展示一下你对光标(或它返回的数据)做了什么吗?其实运行纯SQL语句和打开同一个查询的游标应该没有区别。
-
@TurtlesAllTheWayDown - 还没有听说过“流水线”功能,但现在会去看看。
-
@GuillermoGarcia,正如我已经提到的,运行 SQL 查询和在 PL/SQL 块中为同一查询打开游标没有区别。此外,打开游标对性能几乎没有影响。一旦您开始读取数据,数据库就会开始为您的查询提供服务。所以,我猜,性能问题是在某个地方。如果没有额外的细节,很难说出它到底是什么。
-
“使用 SQL 语句,返回所有行 (5K+) 而不仅仅是默认的 50,需要 27 秒。通过过程/游标返回需要 5+ 分钟” 这听起来像使用光标的代码有问题。这与您在此处发布的存储过程无关。请发布从游标读取(获取)行的代码,也许有人可以帮助您。
标签: oracle performance plsql oracle-sqldeveloper