【问题标题】:What's the point of parameterized cursors in PL/SQL?PL/SQL 中参数化游标的意义何在?
【发布时间】:2020-06-16 16:08:57
【问题描述】:

有人能解释一下在 PL/SQL 中使用参数化游标而不是仅仅创建一个变量并在内部使用它有什么意义吗?

以下匿名块说明了我的意思:

DECLARE
    num NUMBER := 1;
    CURSOR d1 (p_num IN NUMBER) IS SELECT 'foo' FROM dual WHERE 1 = p_num;
    CURSOR d2 IS SELECT 'foo' FROM dual WHERE 1 = num;
BEGIN
    NULL;
END;

游标 d1 和 d2 在处理/性能/等方面有什么不同吗?

提前致谢。

【问题讨论】:

    标签: sql oracle plsql cursor


    【解决方案1】:

    您可能直到运行时才知道您的 p_num 值。它可能是您从其他处理、另一个表、客户端环境或以某种方式计算得到的东西。

    举个简单的例子:

    declare
      cursor c1 is
        select * from departments;
      cursor c2 (p_department_id employees.department_id%type) is
        select * from employees
        where department_id = p_department_id;
    begin
      for r1 in c1 loop
        -- do something with this department info
        dbms_output.put_line(r1.department_name);
    
        -- now loop through empoyees in that department
        for r2 in c2 (r1.department_id) loop
          -- do something with this employee info
          dbms_output.put_line('  ' || r2.first_name);
        end loop;
      end loop;
    end;
    /
    
    Administration
      Jennifer
    Marketing
      Michael
      Pat
    Purchasing
      Den
      Alexander
    ...
    

    c2 光标正在寻找单个部门的员工,但不能硬编码。

    你可以用你的 d2 构造做同样的事情,即分配一个单独的局部变量,内部游标仍将使用 - 因为它正在被重新打开并在此时评估变量:

    declare
      l_department_id departments.department_id%type;
      cursor c1 is
        select * from departments;
      cursor c2 is
        select * from employees
        where department_id = l_department_id;
    begin
      for r1 in c1 loop
        -- do something with this department info
        dbms_output.put_line(r1.department_name);
        -- ...
    
        -- now loop through empoyees in that department
        l_department_id := r1.department_id;
        for r2 in c2 loop
          -- do something with this employee info
          dbms_output.put_line('  ' || r2.first_name);
        end loop;
      end loop;
    end;
    /
    

    ...但是有一个参数可以更清楚地表明预期值会发生变化,并避免进行两次调用而忘记更改其间值的可能性。

    在这两种情况下,游标查询的实际 SQL 将被视为具有绑定变量;不同之处在于它的填充方式。


    显然,您不会真正使用嵌套循环或任何 PL/SQL 来执行此特定任务;并且在很多地方都使用了同样的结构,或者查询至少可以通过连接组合成一个游标。

    它仍然可以用于更复杂的逻辑,例如代码可以采用多条路径和多个可选的辅助游标,并且都需要来自同一个(昂贵的)基本查询的信息,并且您不想重复连接到基本表。

    与大多数逐行处理一样,我怀疑它被滥用的频率超过了真正需要的程度。尽管如此,它仍然是一个有用的工具。

    【讨论】:

    • 谢谢,我明白你的意思了。尽管在您的示例中,我不能提前声明 c2,而只是为 r2 in (select * from employees where department_id = r1.dartment_id) ... 但是如果您想多次使用此游标,您的解释使感觉。谢谢。
    • 当然;但你的问题只是关于explicit cursors。在我的示例中,c1 也可能是隐含的。但是,它根本不需要使用游标......
    • 我知道,我之前曾多次看到它被滥用过很多次,就像我原来的问题一样,我从来没有理解过这一点。你知道这些在处理上有什么不同吗? CBO 或 PL/SQL 引擎对这些有什么影响吗?
    • 在您的 d1 和 d2 示例之间并非如此。两者都可以避免一些硬解析。如果您使用不同的 p_num/num 值多次打开其中任何一个,您将拥有一个硬解析和多个软解析。与我的c2 和您的隐含c2 相同。相反,如果您有多个单独的隐式或显式游标,除了固定值之外它们是相同的,它们将需要对每个游标进行硬解析。
    猜你喜欢
    • 2014-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多