如何计算匿名 plsql 块的上下文切换



对于以下给定的 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;
/

发生上下文切换的原因有很多,包括多任务处理和中断。当谈到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 个用于更新,1 个用于提交。
  2. 有 2 次 FETCH 调用。当你for i in (select * from employee) loop编码时,PL/SQL一次会自动获取100行(以减少上下文切换的数量)。
  3. 有 399 次执行调用:1 次用于 SELECT,199 次用于 UPDATE,199 次用于提交。

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

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

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

此致敬意 炖阿什顿

上下文切换

在执行任何代码块或查询时,如果执行引擎需要从其他引擎获取数据,则称为上下文切换。这里的引擎是指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

干杯!!

最新更新