如何在“流水线表函数”、视图和显式光标之间进行选择

Pie*_*aud 5 oracle plsql

我先说我认为我已经理解的内容。

使用显式游标是因为我们稍后需要重用查询。如果使用非显式游标(即 for cs in (select .........)),则每次使用游标时都会重新执行请求。因此,显式游标用于提高效率。

为了分解代码,我们可以使用“流水线表函数”或“视图”来创建游标。我想知道为什么我应该使用一种解决方案而不是另一种解决方案。

以下是我对这些解决方案的了解:

不赞成也不反对

我可以使用 select 语句提取视图或流水线表函数函数的一部分。

骗局

必须声明“流水线表”使用的记录类型和表类型。这需要时间

pro:我们可以在管道表(例如循环)中使用 pl/sql 语句的所有可能性

我说的都是真的吗?还有其他我应该知道的事情吗?

Chr*_*xon 8

对于这两种游标类型,数据库在打开时执行其中的语句。如果游标保持打开状态,您可以稍后从中获取结果,而无需重新运行它。因此,两者在这方面的效率相同。

显式游标是一种您可以控制其整个生命周期的游标:打开、获取和关闭。使用隐式游标,PL/SQL 会为您处理这个问题。

当您想要完全控制提取过程时,您可以使用显式游标。此批量收集的主要用例有限制

如果您想在应用程序的许多地方使用相同的查询,显式游标也很方便。在包级别声明它,你可以在任何你喜欢的地方引用它:

create or replace package pkg as 
  cursor common_cursor is 
    select ...
end;
Run Code Online (Sandbox Code Playgroud)

这为查询提供了单一定义,这可以使您的代码更易于维护。这样做的问题是,无论在何处使用它,您都需要打开、获取和关闭它。在大多数情况下,这会导致更多的代码而收益最小。

这让我们看到了观点。您可以将公共查询放在视图中,而不是声明公共游标:

create or replace view common_query as 
  select ...;
Run Code Online (Sandbox Code Playgroud)

然后,您可以像普通表一样在任何其他 SQL 语句中使用它。所以你可以加入它,等等。你不能直接用显式游标来做到这一点。您必须将其包装在(流水线)表函数中

create or replace function pipetf
  return ...
  pipelined 
as
  retvals ...;
begin
  open pkg.common_cursor;
  loop
    fetch pkg.common_cursor
    bulk collect into retvals limit 100;
    
    exit when retvals.count = 0;
      
    for i in 1 .. retvals.count loop
      pipe row ( retvals ( i ) ) ;
    end loop;
  end loop;
  close pkg.common_cursor ;
  return;
end pipetf;
/
Run Code Online (Sandbox Code Playgroud)

这允许您在另一个 SQL 语句中使用游标,如视图:

select * from pipetf;
Run Code Online (Sandbox Code Playgroud)

在这一点上,流水线表函数似乎比视图更简单。那么何必呢?

好吧,它允许您做视图不能(轻松)做的事情:

  • 生成新行或按程序操作结果集
  • 创建参数化查询

一般来说,您不能将变量传递给像这样的查询视图(有一些方法,但它们带有陷阱):

select c2 from ...
where  c1 = :var
group  by c2;
Run Code Online (Sandbox Code Playgroud)

而您可以在显式游标中:

cursor common_cursor ( var int ) is 
  select c2 from ...
  where  c1 = var
  group  by c2;
Run Code Online (Sandbox Code Playgroud)

所以你可以在 PTF 中使用它来创建一个可重用的参数化查询:

create or replace function pipetf ( var int )
  return ...
  pipelined 
as
  retvals ...;
begin
  open pkg.common_cursor ( var );
  loop
    fetch pkg.common_cursor
    bulk collect into retvals limit 100;
    
    exit when retvals.count = 0;
      
    for i in 1 .. retvals.count loop
      pipe row ( retvals ( i ) ) ;
    end loop;
  end loop;
  close pkg.common_cursor ;
  return;
end pipetf;
/
Run Code Online (Sandbox Code Playgroud)

因此,如果您需要使用 PL/SQL 来创建新行、操作查询结果或想要可重用的参数化查询,那么流水线表函数是您的最佳选择。

为什么?

Oracle Database 18c 添加了多态表函数,其中涵盖了许多行生成/结果操作示例。从 19.6 开始,您可以创建 SQL 宏,用于模拟参数化视图。这些功能涵盖了大多数(全部?)流水线表函数(以及更多)的用例。

如果您只需要一个无需额外处理的可重用查询,我会坚持使用视图。