Oracle Scalar Subquery Cache

本文为翻译贴,原文章请见:

http://www.oracle.com/technetwork/issue-archive/2011/11-sep/o51asktom-453438.html

Tom Kyte介绍了OracleScalarSubquery Cache特性,并将之与determinstic function, function result cache做了性能比较。

所谓Scalar Subquery意即标量子查询,至多只返回一行,一列数据的子查询,常常出现在Select部分。例:

Select emp.ename, (select dept.dname from dept where dept.deptno=emp.deptno)

From emp;


与以上 select语句等价的是:
Select emp.ename, dept.dname

From emp left outer join dept on(emp.deptno=dept.deptno).

因为标量子查询可以返回0条记录,故而在第二条语句中应该是左连接。在运行时,这条语句形如:

Select emp.ename, (select dept.dname from dept where dept.deptno=:deptno)

From emp;
Oracle将循环地取出 emp表中所有 deptno,并将其作为绑定变量值传入标量子查询 (Scalar Subquery)。在 Oracle 10g以上版本中, Oracle会维护一个大小( Slot size255的哈希表。这个哈希表的 key是标量子查询的输入:绑定变量 :deptnovalue是标量子查询的输出: dept.dname。假如哈希表里已经存在某个 deptno,那么 Oracle就直接取 value,而不需要重复执行标量子查询语句。

当出现哈希冲撞时,后来的deptno将不会占据该slot。但是Oracle维护一个”last_key_value”变量,当连续出现重复deptno时,即使有哈希冲撞,Oracle将取出last_key_value的值,而不需要重复执行标量子查询。

下面比较下标量子查询,deterministic函数, result_cache函数在执行时间方面的差异。

create or replace function f( x in varchar2) return number

as

begin

  dbms_application_info.set_client_info(userenv('client_info')+1 );

  return length(x);

end;

create or replace function f_d( x invarchar2 ) return number

DETERMINISTIC

as

begin

  dbms_application_info.set_client_info(userenv('client_info')+1 );

  return length(x);

end;

create or replace function f_rc( x invarchar2 ) return number

result_cache

as

begin

  dbms_application_info.set_client_info(userenv('client_info')+1 );

  return length(x);

end;

set timing off

SET FEEDBACK OFF

set serveroutput on;

set arraysize 150

set linesize 120

set pagesize 150

variable v_start number;

col client_info format a10

select * from v$version;

--ordinary function

execdbms_application_info.set_client_info(0);

exec :v_start := dbms_utility.get_cpu_time;

set termout off;

select owner, f(owner) from stage;

set termout on;

exec dbms_output.put_line('Ordinaryfunction');

select dbms_utility.get_cpu_time-:v_startcpu_hsecs, userenv('client_info') client_info from dual;

--Deterministic function

execdbms_application_info.set_client_info(0);

exec :v_start := dbms_utility.get_cpu_time;

set termout off;

select owner, f_d(owner) from stage; 

set termout on;

exec dbms_output.put_line('Deterministicfunction');

select dbms_utility.get_cpu_time-:v_startcpu_hsecs, userenv('client_info') client_info from dual;

--Function result cache

execdbms_application_info.set_client_info(0);

exec :v_start := dbms_utility.get_cpu_time;

set termout off;

select owner, f_rc(owner) from stage; 

set termout on;

exec dbms_output.put_line('Function resultcache');

select dbms_utility.get_cpu_time-:v_startcpu_hsecs, userenv('client_info') client_info from dual;

--Scalar Subquery

execdbms_application_info.set_client_info(0);

exec :v_start := dbms_utility.get_cpu_time; 

set termout off;

select owner, (select f(owner) from dual)from stage; 

set termout on;

exec dbms_output.put_line('ScalarSubquery');

select dbms_utility.get_cpu_time-:v_startcpu_hsecs, userenv('client_info') client_info from dual;
BANNER

----------------------------------------------------------------------------

Oracle Database 11g Enterprise EditionRelease 11.2.0.1.0 - 64bit Production

PL/SQL Release 11.2.0.1.0 - Production

CORE   11.2.0.1.0      Production

TNS for Linux: Version 11.2.0.1.0 -Production

NLSRTL Version 11.2.0.1.0 - Production

Ordinary function

 CPU_HSECS CLIENT_INF

---------- ----------

      202 74236

Deterministic function

 CPU_HSECS CLIENT_INF

---------- ----------

       25 996

Function result cache

 CPU_HSECS CLIENT_INF

---------- ----------

      145 0

Scalar Subquery

 CPU_HSECS CLIENT_INF

---------- ----------

       13 70
说明:这是第二次跑,f_rc部分数据有点失真。
结论:
1.标量子查询耗时最少
2.即使Function Result Cache能减少函数运算,但是耗时远大于Deterministic和Scalar Subquery,很可能是SQL-PL/SQL Context Switch造成的。
3.当结果集较大时,使用形如:select x, (select f(x) from dual) from table的SQL是个好习惯。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值