Сравнение скорости функций user vs sys_context('USERENV','SESSION_USER')


Сегодня очень удивился заметив, что вызов "username:=user;" и "select user into username from dual;" одинаковы по времени выполнения, в отличие от десятикратной разницы dt:=sysdate и select sysdate into dt from dual;. Оказалось все просто, стоило лишь поглядеть трассировку или поглядеть код пакета sys.standard: PL/SQL-ный USER содержит внутри рекурсивный запрос c вызовом sql-ного user: "select user from sys.dual".
Из кода standard:
function USER return varchar2 is
  c varchar2(255);
  begin
        select user into c from sys.dual;
        return c;
  end;

  -- Bug 1287775: back to calling ICD.
  -- Special: if the ICD raises ICD_UNABLE_TO_COMPUTE, that means we should do
  -- the old 'SELECT SYSDATE FROM DUAL;' thing.  This allows us to do the
  -- SELECT from PL/SQL rather than having to do it from C (within the ICD.)
  function sysdate return date is
    d date;
  begin
    d := pessdt;
    return d;
  exception
    when ICD_UNABLE_TO_COMPUTE then
      select sysdate into d from sys.dual;
      return d;
  end;

  -- Special: if the ICD raises ICD_UNABLE_TO_COMPUTE, that means we should do
  -- the old 'select sys_context(...) from dual;' thing.  This allows us to do
  -- the select from PL/SQL rather than having to do it from C (within the ICD.)
  function SYS_CONTEXT(namespace varchar2, attribute varchar2)
    return varchar2 is
  c varchar2(4000);
  BEGIN
    c := pessysctx2(namespace, attribute);
    return c;
  exception
    when ICD_UNABLE_TO_COMPUTE then
      select sys_context(namespace,attribute) into c from sys.dual;
      return c;
  end;

И самое главное: user в 10 раз с лишним медленнее, чем sys_context('USERENV','SESSION_USER')!
У user, видимо, все это время съедает переключение контекста, а исключение ICD_UNABLE_TO_COMPUTE в sys_context непроисходит(как и в случае с sysdate).

Я проверял на 10.2.0.4, 10.2.0.5, 11.2.0.1, 11.2.0.3 с plsql_optimization_level=2 результаты практически одинаковы, поэтому показываю только один:

DB11G/XTENDER> declare
  2    username varchar2(30);
  3  begin
  4    for i in 1..5e5 loop
  5      username:=user;
  6    end loop;
  7  end;
  8  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:10.86
DB11G/XTENDER> declare
  2    username varchar2(30);
  3  begin
  4    for i in 1..5e5 loop
  5      username:=sys_context('USERENV','SESSION_USER');
  6    end loop;
  7  end;
  8  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:01.02

Comments

Отправить комментарий