Oracle SQL 和 PL/SQL 上下文切换

Vin*_*eja 3 oracle plsql

我在oracle pl sql中有一段代码,想真正了解一下有多少上下文切换

If x=0 then 

  curserx= select a from mytable1;

Else

  curserx=select a from mytable1 where id=:x;

End;

Loop

  Fetch on cursorx

  Select c from mytable2 where a=curserx.a;

End loop;
Run Code Online (Sandbox Code Playgroud)

这只是一个示例代码,所以请原谅任何文本大小写和逻辑错误。

Ste*_*ein 5

我将您的伪代码转换为 PL/SQL 并包含注释,表明我相信您将在何处进行从 PL/SQL 引擎到 SQL 引擎的上下文切换。

请注意,如果您要查询大量行,则可以使用 FETCH BULK COLLECT INTO 并在每次提取时检索多行,从而大大减少上下文切换。

DECLARE
   l_x_value   INTEGER;
   l_cursor    SYS_REFCURSOR;
   l_fetched   mytble1.a%TYPE;
BEGIN
   /* context switch to open */
   IF x = 0
   THEN
      OPEN l_cursor FOR SELECT a FROM mytable1;
   ELSE
      OPEN l_cursor FOR
         SELECT a
           FROM mytable1
          WHERE id = l_x_value;
   END IF;

   LOOP
      /* context switch per fetch */
      FETCH l_cursor INTO l_fetched;

      EXIT WHEN l_cursor%NOTFOUND;

      /* context switch for implicit cursor */
      SELECT c
        INTO l_fetched
        FROM mytable2
       WHERE a = curserx.a;
   END LOOP;

   /* context switch to close */
   CLOSE l_cursor;
END;
Run Code Online (Sandbox Code Playgroud)

但这还不是全部!请记住,上下文切换是双向的:SQL -> PL/SQL 和 PL/SQL -> SQL。您可以通过使用 UDF pragma (12c+) 声明函数或使用 WITH FUNCTION 子句(也是 12c+)定义函数来减少从 SQL 到 PL/SQL 的开销。仍然有一个上下文切换,但一些工作是在编译时而不是运行时完成的。

所以在下面的代码中,对于从 SELECT 中调用函数的每次,都有一个开关。

CREATE OR REPLACE FUNCTION full_name (first_in   IN VARCHAR2,
                                      last_in    IN VARCHAR2)
   RETURN VARCHAR2
IS
BEGIN
   RETURN first_in || ' ' || last_in;
END;
/

DECLARE
   l_name   VARCHAR2 (32767);
BEGIN
   SELECT full_name (first_name, last_name) INTO l_name 
     FROM employees
    WHERE employee_id = 100;

   DBMS_OUTPUT.PUT_LINE (l_name);
END;
/
Run Code Online (Sandbox Code Playgroud)

最后一个警告:您应该尽一切努力避免在随后从 SQL 调用的函数中执行 SQL。适用于您的 SQL 语句的标准读取一致性模型不会“带入”到函数的 SQL 中。换句话说,如果您“外部” SELECT 在 10:00 开始运行并运行一个小时,并且在 10:05,有人会从外部查询和函数中的查询中使用的表中删除行(和提交),这两个查询将使用这些表的不同状态。