bind函数oracle,说说Oracle Bind Graduation(下)

上篇(http://space.itpub.net/17203031/viewspace-704144)中,我们解释了与bind peeking等价的Oracle绑定变量技术bind graduation。本篇中,我们继续深入探讨该技术,和思考在bind graduation的环境下我们应用开发应该注意些什么。

1、声明值还是实际值?

上面的实验,告诉我们在执行PL/SQL绑定变量时,会出现绑定变量元数据metadata分区的情况。那么,究竟是我们声明variable的变量引发的graduation,还是我们对变量赋值引发的graduation。我们就用上面发现的32 bytes分区作为实验对象。

SQL> declare

2n number(10);

3v varchar2(33);

4begin

5n := 14;

6v := 'Tom Kyte'; //v值显然不足32bytes;

7

8execute immediate 'insert /*+ bind_data_plsql */into t values (:x, :y)'

9using n, v;

10commit;

11

12v := lpad('Tom Kyte',33,'_');//达到33 bytes;

13

14execute immediate 'insert /*+ bind_data_plsql */into t values (:x, :y)'

15using n, v;

16commit;

17end;

18/

PL/SQL procedure successfully completed

此时,我们观察一下游标使用的情况。判断在相同的声明variable的情况下,游标是否发生共享。注意:本实验是在上面实验的基础上进行。

SQL> select sql_text, sql_id, address, version_count, EXECUTIONS fromv$sqlarea where sql_text like 'insert /*+ bind_data_plsql */%';

SQL_TEXTSQL_IDADDRESSVERSION_COUNT EXECUTIONS

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

insert /*+ bind_data_plsql */into t values (:x, :y) a765qwfk986aj 4D74ECA824

SQL> select sql_id, child_number, address, child_address,executionsfrom v$sql where sql_id='a765qwfk986aj';

SQL_IDCHILD_NUMBER ADDRESSCHILD_ADDRESS EXECUTIONS

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

a765qwfk986aj0 4D74ECA8 4D74EA241

a765qwfk986aj1 4D74ECA8 49D19D5C3

增加的两次执行,全部落在了child_number=1的子游标上。我们再次观察该子游标对应的绑定变量元数据。

SQL> select * from v$sql_bind_metadata where address='49D19D5C';

ADDRESSPOSITIONDATATYPE MAX_LENGTHARRAY_LEN BIND_NAME

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

49D19D5C211280 Y

49D19D5C12220 X

显然,超过了32bytes的绑定变量定义,都是落在了128上限的元数据metadata分区上。自然也就共享child_number=1的子游标。我们实验的目的也就达到了,Oracle在进行bind graduation的时候,使用的是PL/SQL绑定变量的声明类型长度。

2、上限

上面的一系列实验,让我们看到了对字符绑定变量,在执行PL/SQL代码时存在[0-32],[33-128]至少两个分区。那么,varchar2的长度上限是4000。这个范围内,还存在什么分区呢?我们通过实验来确定。

SQL> declare

2n number(10);

3v varchar2(500); //增加到500长度;

4begin

5n := 14;

6v := 'Tom Kyte';

7

8execute immediate 'insert /*+ bind_data_plsql */into t values (:x, :y)'

9using n, v;

10commit;

11end;

12/

PL/SQL procedure successfully completed

当我们定义增加到500,实验游标情况。

SQL> select sql_id, child_number, address, child_address, executionsfrom v$sql where sql_id='a765qwfk986aj';

SQL_IDCHILD_NUMBER ADDRESSCHILD_ADDRESSEXECUTIONS

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

a765qwfk986aj0 4D74ECA8 4D74EA241

a765qwfk986aj1 4D74ECA8 49D19D5C3

a765qwfk986aj2 4D74ECA8 49D06E6C2(实验中,上面代码执行两次)

SQL> select * from v$sql_bind_metadata where address='49D06E6C';

ADDRESSPOSITIONDATATYPE MAX_LENGTHARRAY_LEN BIND_NAME

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

49D06E6C2120000 Y

49D06E6C12220 X

在128 bytes之上,我们发现了第三个分区上限2000。也就是[128-2000]以内,是一个graduation范围。那么,在提高绑定变量声明长度,能否探查到新的分区了呢?

SQL> declare

2n number(10);

3v varchar2(2500);

4begin

5n := 14;

6v := 'Tom Kyte';

(篇幅原因,有省略……)

观察执行child cursor情况。

SQL> select sql_id, child_number, address, child_address,executionsfrom v$sql where sql_id='a765qwfk986aj';

SQL_IDCHILD_NUMBER ADDRESSCHILD_ADDRESS EXECUTIONS

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

a765qwfk986aj0 4D74ECA8 4D74EA241

a765qwfk986aj1 4D74ECA8 49D19D5C3

a765qwfk986aj2 4D74ECA8 49D06E6C3

依然共享2000上限游标。注意:虽然游标child_number=2的max length列标注的是2000,我们声明长度2500的时候,依然实现了共享。

SQL> declare

2n number(10);

3v varchar2(3000);

4begin

5n := 14;

6v := 'Tom Kyte';

实现使用3000的时候,依然共享了上限2000的child cursor。

SQL> select sql_id, child_number, address, child_address, executionsfrom v$sql where sql_id='a765qwfk986aj';

SQL_IDCHILD_NUMBER ADDRESSCHILD_ADDRESSEXECUTIONS

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

a765qwfk986aj0 4D74ECA8 4D74EA241

a765qwfk986aj1 4D74ECA8 49D19D5C3

a765qwfk986aj2 4D74ECA8 49D06E6C4

经过上面的实验,我们发现了bind graduation在变量长度变化时的一些特性。在128bytes之上,还存在一个有效的2000作为游标上限。突破2000之后,绑定变量的metadata数据上限始终显示2000。之后,即使我们声明变量长度超过2000,也是会共享这个2000的子游标。说明,当字符类型绑定变量长度声明超过了2000之后,bind graduation机制失去了效果。所有变量共享一个元数据cursor。

5、结论与思考

经过上面的实验,我们虽然没有证明《Troubleshooting》作者实验的SQL下bind graduation现象。但是起码证明了在Oracle 11gR2的情况下,PL/SQL使用字符绑定变量时,还是存在bind graduation现象的。笔者在思考一个问题,作为与bind peeking相同定位的bind graduation,Oracle推出它的意义何在呢?

经过和其他同事的讨论,认为可能原因有如下两个:

übind peeking缓解,提供多次peeking机会

从效果来看,Oracle bind graduation会增加子游标的数量。如果单就bind peeking而言,在Oracle 11g的ACS(Adaptive Cursor Sharing)出现之前,Oracle绑定变量使用的子游标数量是很少的。

Bind graduation出现之后,我们最直观的感觉是child cursor增多,对应的执行计划增多。原有的可能只用一个执行计划可以覆盖的绑定变量语句,可能要有多个执行计划才能覆盖。

对绑定变量语句而言,每次生成子游标,就意味着要进行一次hard parse,就意味着要进行一次peeking。生成与Peeking value对应的执行计划。PL/SQL代码中对变量声明长度的不一致,直接意味着不同的程序模块和功能模块。Oracle也许认为这样出现bind peeking问题的几率较高。于是取巧采用变量声明的方式进行区分管理。同时,划分区域又不是很多,从而限制了子游标出现的数量。多次peeking,形成多个子游标,配对更合适的执行计划。

ü绑定变量存储

对执行计划而言,Oracle是需要单独分配内存空间给执行计划进行保存的。如果其中有使用绑定变量,Oracle是会将绑定变量保存在child cursor中的。在分配varchar2类型的绑定变量大小空间时,使用bind graduation可以分配略小的适当空间。

最后,我们聊聊bind graduation的实际意义,主要是针对pl/sql程序而言的。虽然会存在bind graduation现象,但是我们说实现graduation的分区数量是有限的。也就是说,即使多次生成child cursor,带来version count过多的风险也是有限的。

如果要是很极端的情况,比如项目组希望实现绝对的共享或者说变量数目较多引起version count过多,可以使用10503事件控制bind graduation的出现,或者直接在代码中声明varchar2(2000)的绑定变量即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值