如果我在 SQL*Plus 中设置 ARRAYSIZE 1,记录仍然是成对提取的。为什么?

Ren*_*ger 7 oracle sqlplus

我想写一个简单的 tail -f实用程序来“跟踪”数据库中某些数字的进度:

create or replace function tail_f return varchar2_tab pipelined as
   n number;
begin

    loop
      exit when ...

      select count(*) into n from ... where ...;

      pipe row(sysdate || ' n= ' || n);
      dbms_lock.sleep(60);
    end loop;

    return;
end tail_f;
Run Code Online (Sandbox Code Playgroud)

然后我想select * from table(tail_f)在 SQL*Plus 中。

为了一一获取行,我SET ARRAYSIZE 1. 然而,记录(第一个除外)是成对获取的。

对此是否有解释,以及如何在通过管道传输后立即获取记录?

Phi*_*lᵀᴹ 9

Metalink 错误 9103343 指出:

这是预期的行为。SQL*Plus 是用 oci 编写的,oci 的默认预取值为 1 行。然而,预取时(而不是执行时)仅在您不执行数组提取时发生,因此当 arraysize 为 1 时。无论数组大小如何,跟踪中的第一个提取始终为 1 行,因为 1 行是预取的执行。然后它要么执行标量提取,所以一个请求的行加上一个预取的行,或者它执行一个数组提取,所以你看到例如:a) arraysize = 1,提取是:1, 2, 2, ... b) arraysize = 2, fetches 是: 1, 2, 2, ... c) arraysize = 5, fetches 是: 1, 5, 5, ...

另请参阅 Metalink 文档 1265916.1


Jac*_*las 5

这似乎是 SQL*Plus 的一个怪癖,arraysize而不是流水线函数 - 下面演示了相同的效果:

create or replace function pause return integer as
begin
  dbms_lock.sleep(2);
  return 1;
end;
/

select pause from dual connect by level<10;
Run Code Online (Sandbox Code Playgroud)

您可以(某种程度上)通过选择行两次并每隔一秒丢弃一次来解决该问题:

select /*+ ordered first_rows(1) */ *
from table(tail_f) cross join (select level from dual connect by level<=2);
Run Code Online (Sandbox Code Playgroud)