1

下面给定的 plsql 块将发生多少次上下文切换

    Declare
    ll_row_count number := 0;
    begin
    for i in (select * from employee) 
    loop
    ll_row_count := ll_row_count+1;
    update employee
    set emp_name = upper(emp_name)
    where emp_id = i.emp_id;
    commit;
    end loop;
    dbms_output.put_line('Total rows updated' || ll_row_count);
    end;
/
4

2 回答 2

2

发生上下文切换的原因有很多,包括多任务处理和中断。说到Oracle数据库开发,我们一般只指PL/SQL引擎和SQL引擎之间的切换

在您的示例中,PL/SQL 正在调用 SQL。当 PL/SQL 调用 SQL 时有一次上下文切换,当 SQL 返回到 PL/SQL 时有第二次上下文切换。

PL/SQL 调用 SQL 来解析语句、执行语句或从查询中获取行。我们可以使用 SQL 跟踪工具和称为 TKPROF 的跟踪分析器来测量调用次数。

我创建了一个包含 199 行的表并跟踪了您的代码的执行:

  1. 有 3 个 PARSE 调用:1 个用于 SELECT,1 个用于 UPDATE,1 个用于 COMMIT。
  2. 有 2 个 FETCH 调用。当您编写代码时for i in (select * from employee) loop,PL/SQL 将自动一次获取 100 行(以减少上下文切换的次数)。
  3. 有 399 个 EXECUTE 调用:1 个用于 SELECT,199 个用于 UPDATE,199 个用于 COMMIT。

所以从 PL/SQL 到 SQL 有 404 次调用,从 SQL 到 PL/SQL 有 404 次返回,总共进行了 808 次上下文切换

我们可以通过在循环后提交一次来将上下文切换的数量减少一半。强烈建议避免过于频繁的提交。如果您在 SELECT 循环中提交,您可能会得到与 UNDO 相关的异常不再可用。

通常,减少上下文切换和提高性能的最佳方法是使用基于集合的 SQL。如果做不到这一点,我们可以使用 BULK COLLECT 和 FORALL 一次处理一堆行。

最好的问候,炖阿什顿

于 2019-08-12T13:50:36.687 回答
0

上下文切换

在执行任何代码块或查询时,如果执行引擎需要从其他引擎获取数据,则称为上下文切换。这里的引擎指的是SQL引擎和PL/SQL引擎。

意思是,在PL/SQL中执行你的代码时,如果有一条SQL语句,那么PL/SQL引擎需要把这条SQL语句传递给SQL引擎,SQL引擎获取结果并将其传递回PL/SQL引擎。因此,发生了两个上下文切换。

现在,来到你的街区,请参阅内联评论。我们将N用作表中的记录数employee

Declare
ll_row_count number := 0;
begin
for i in (select * from employee) -- (CEIL(N/100)*2) context switch
loop
ll_row_count := ll_row_count+1;
update employee
set emp_name = upper(emp_name)
where emp_id = i.emp_id;  -- 2*N context switch
commit; -- 2*N context switch
end loop;
dbms_output.put_line('Total rows updated' || ll_row_count);
end;
/

现在,为什么我们将 N 除以 100?

因为在 oracle 10g 及以上版本中 For 循环被优化为使用 LIMIT 100 的批量事务来减少循环中的上下文切换。

所以最后,上下文切换的数量是:(CEIL(N/100)*2) + 2*N + 2*N

干杯!!

于 2019-08-11T05:46:33.423 回答