绑定变量窥视功能是数据库的一个特性,自ORACLE9i版本开始引入,默认是开启的。

“绑定变量窥视”表示,查询优化器在第一次调用游标时,会观察用户定义的绑定变量的值,允许优化器来确认过滤条件的选择性,以及是否使用绑定变量代替了常量。之后调用游标时不会出现窥视,且会根据指针共享标准来共享游标,即使随后的调用使用不同的绑定值。

使用绑定变量窥视,第一次解析包含绑定谓词的SQL语句时,优化器将查看绑定变量的值,并使用该值为查询创建执行计划。然后,不管更改的绑定值如何,该计划都将被存储并用于未来的所有执行。如果初始绑定值不能很好地代表将来执行查询时提供的其他值,那么,即使当前访问路径较优,也可能导致未来执行变差,甚至影响某些迭代的查询性能变慢。

上面的特性是由参数"_optim_peek_user_binds"驱动的,如果禁用这个数据库特性,已经执行过的这类值的执行计划将不会发生变化,但还有一个可能性,一个新值能创造一个更优的执行计划。

本次技术分享,就是,绑定变量窥视参数"_optim_peek_user_binds"对SQL执行计划的影响。在不同的场景下,合理设置"_optim_peek_user_binds"参数,具有重大的实践意义。之前,美创某客户核心系统,就出现过由于"_optim_peek_user_binds"参数设置而引发该核心系统SQL执行出现性能问题。

接下来,我们就来具体了解下,如何在不同场景下充分利用绑定变量窥视这一功能。

首先,来创建一张CONTEXT列数据分布倾斜的TEST表。

SQL> drop table test;

SQL> create table test(id number,context varchar2(20));

SQL> declare

2  begin

3  for i in 1..20000 loop

4  insert into test values(i,'peek_binds');

5  end loop;

6  commit;

7  end;

8  /

PL/SQL procedure successfully completed.

SQL> declare

2  begin

3  for i in 20001..20010 loop

4  insert into test values(i,'peek_binds_01');

5  end loop;

6  commit;

7  end;

8  /

PL/SQL procedure successfully completed.

接着,在TEST.CONTEXT列上创建TEST_INDEX普通索引。

SQL> create index test_index on test(context);

索引创建完成之后, 由于TEST.CONTEXT列数据分布比较倾斜,在收集TEST表统计信息的同时,也要收集TEST.CONTEXT字段的柱状图信息,以便优化器产生最优的执行计划。

SQL> exec dbms_stats.gather_table_stats(ownname=>'XUH',tabname=>'TEST',estimate_percent=>100,method_opt => 'for all indexed columns',Degree=>8,Cascade=>TRUE,Granularity=>'ALL');

之前创建的TEST表有20010行数据,其中CONTEXT列peek_binds值20000行、peek_binds_01值10行。理论上,当过滤条件中代入peek_binds值,执行计划走的是全表扫描;代入peek_binds_01时,执行计划走的是索引。

SQL> set lines 299 pages 9999

SQL> set autotrace traceonly

SQL> select * from test where context='peek_binds';

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

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

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

|*  1 |  TABLE ACCESS FULL| TEST | 20000 |   292K|    17   (0)| 00:00:01 |

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

SQL> select * from test where context='peek_binds_01';

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

| Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |

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

|*  2 |   INDEX RANGE SCAN     | TEST_INDEX |    10 |       |     1   (0)| 00:00:01 |

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

当然,为了验证如上SQL的执行计划是否为最佳的执行计划,可以通过hint方式,强制同样的SQL语句走不同的执行计划,并比较执行的成本。对比分析之后,不难发现上述SQL语句采用的均是最佳的执行计划。

SQL> select /*+ INDEX(TEST TEST_INDEX)*/ count(*) from test where context='peek_binds';

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

| Id  | Operation         | Name       | Rows  | Bytes | Cost (%CPU)| Time     |

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

|*2 | INDEX RANGE SCAN| TEST_INDEX | 20000 |234K| 62 (0)| 00:00:01| --------------------------------------------------------------------------

SQL> select /*+ FULL(TEST)*/ * from test where context='peek_binds_01';

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

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

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

|*  1 |  TABLE ACCESS FULL| TEST |    10 |   150 |    17   (0)| 00:00:01 |

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

若想对TEST_INDEX索引的使用情况进行监控,可使用如下ALTER命令开启监控。

alter index TEST_INDEX monitoring usage;

select * from v$object_usage;

以上,我们分析了一张基于列数据分布非常倾斜的表,进行数据分布不一致列值的查询,以及相关SQL获取最佳的执行计划。

接下来,进入正题,上面案例中过滤条件均是以常量的方式代入,相关SQL都能按最优的执行计划执行。那么,当以变量的方式将数据分布不一致列值代入时,SQL的执行计划会如何呢?

先检查下隐含参数"_optim_peek_user_binds"的当前值,确认当前值和默认值均为TRUE,也就是说绑定变量窥视特性,在默认情况下是开启的。要想在数据库级别将绑定变量窥视特性关闭,需修改该参数"_optim_peek_user_binds"为FALSE,并重启实例。

SQL> select

2  a.ksppinm   name,

3  b.ksppstvl  value,

4  b.ksppstdf  isdefault

5  from

6  sys.x$ksppi a,

7  sys.x$ksppcv b

8  where

9  a.inst_id = userenv('Instance') and

10  b.inst_id = userenv('Instance') and

11  a.indx = b.indx and a.ksppinm ='_optim_peek_user_binds'

12  order by

13  translate(a.ksppinm, ' _', ' ')

14  /

NAME                  VALUE   ISDEFAULT

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

_optim_peek_user_binds    TRUE    TRUE

现在,来定义一个变量A,并将列值peek_binds传入,检查该SQL语句的执行计划,发现采用的执行计划是全表扫描,跟预期相符。紧接着,将列值peek_binds_01传入,发现采用的执行计划是依然是全表扫描,这种现象完全符合绑定变量窥视参数特性的预期,即在绑定变量窥视参数特性启用期间,以绑定变量方式执行的SQL,第一次执行所产生的执行计划,作为该类SQL后续执行的计划。当出现这种情况,意味着第二条SQL类型语句的执行效率降低、响应时间变长。在某些极端的情况下,势必会造成数据库性能问题。

SQL> set autotrace traceonly

SQL> var A varchar2(20);

SQL> exec :A :='peek_binds';

SQL> select * from test where context=:A;

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

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

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

|*  1 |  TABLE ACCESS FULL| TEST | 10005 |   146K|    17   (0)| 00:00:01 |

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

SQL> exec :A :='peek_binds_01';

SQL> select * from test where context=:A;

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

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

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

|*  1 |  TABLE ACCESS FULL| TEST | 10005 |   146K|    17   (0)| 00:00:01 |

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

当然,使用AUTOTRACE跟踪,没有实际真正执行,SQL语句执行计划存在不准确的情况。那么,可以在实际执行多次之后,检查CURSOR中缓存的执行计划来进行确认。发现不论传入何值、不论执行次数,该类SQL语句始终只有一个执行计划。

SQL> select sql_id,address,hash_value,plan_hash_value from v$sql where sql_text like 'select * from test where context=:A';

SQL_ID          ADDRESS            HASH_VALUE  PLAN_HASH_VALUE

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

8avvyuyr2m1w7 000000194F6C2460 2921957255  1357081020

SQL> select * from table(DBMS_XPLAN.DISPLAY_CURSOR('8avvyuyr2m1w7'));

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

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

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

|*  1 |  TABLE ACCESS FULL| TEST | 20000 |   292K|    17   (0)| 00:00:01 |

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

验证了绑定变量窥视参数特性在某些场景下存在的局限性,那么将绑定变量窥视参数特性关闭掉,又会发生些什么呢?

手动将之前该类型SQL语句的执行计划刷出内存,通过hint方式,将隐含参数"_optim_peek_user_binds"强制为false,传入列值peek_binds_01,并执行该类SQL。发现特性禁用之后,传入新值,产生了新的、更优的执行计划,效率更高、成本更低。这里列了以下三种方式可以清除SQL执行计划,分别是DBMS包、FLUSH命令和GRANT语句等。

SQL> exec dbms_shared_pool.purge('000000194F6C2460,2921957255','C',1);

或者

SQL> alter system flush shared_pool;

或者

SQL> grant select on test to xuh;

SQL> exec :A :='peek_binds_01';

SQL> select /*+opt_param('_optim_peek_user_binds', 'false')*/ * from test where context=:A;

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

| Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |

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

|*  2 |   INDEX RANGE SCAN     | TEST_INDEX |    10 |       |     1   (0)| 00:00:01 |

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

总结来说,"_optim_peek_user_binds",该参数默认为TRUE。这就意味着,第一次以变量的方式执行某类SQL时,会生成第一个执行计划,后续执行该类SQL语句,即使变量的传入值不同,但因变量窥视的作用,依然会沿用第一次SQL语句执行时生成的执行计划,这种特性非常适用于业务表数据分布比较均匀的场景,执行计划比较稳定。但对于数据分布严重倾斜的业务表,固定的执行计划,就有可能降低SQL的执行效率,引起前端响应时间变慢等。在极端情况下,会引发严重的性能问题。

当"_optim_peek_user_binds"参数设置为FALSE。即,将绑定变量窥视参数特性禁用。那么已经执行过的某类值的执行计划将不会发生变化,一旦传入某个新值时,优化器会自动根据被访问对象的统计、直方图等信息,产生它认为效率最高、成本最低的执行计划。也就是说,在特性关闭的情况下,该类SQL语句可能会产生更优的执行计划。

转载自:

https://mp.weixin.qq.com/s?__biz=MzA3MTUzNzcwMg==&mid=2649875512&idx=2&sn=da14abca7b373b50e05f4e06bef809ee&chksm=87294171b05ec8672c20afa3a011294c463027b38b4f97de99b50544c2959dfd76e3105c8461&mpshare=1&scene=1&srcid=0809eJkUs2L5HFWhGTJcV9lQ&sharer_sharetime=1565314308951&sharer_shareid=4ea1bc090eabbee4a82e6650a49c5a55&key=0f0abb20a7092e0c8a0339818d201659f9bb7ae7a7ac977473a567731b6cde5f6d729b9f35b289f1b744c46da7771e76de1a0f71c8ace7d3f7a01759fc4d011f1e5fca871429932c158a685c0dd4104d&ascene=1&uin=MjYzMDM4NzYwNA%3D%3D&devicetype=Windows+10&version=62060833&lang=zh_CN&pass_ticket=HIf2NM7kc6R81B4sqhYSmlRwDgDubQA09ctMMoG%2FChvy%2FaF2%2FyxNyfkVftmfHLLH

Oracle 绑定变量窥视的更多相关文章

  1. Oracle ACS 绑定变量窥视 条件

    1. ACS简介 Oracle Database 11g提供了Adaptive Cursor Sharing (ACS)功能,以克服以往不该共享的游标被共享的可能性.ACS使用两个新指标:sensit ...

  2. SQL优化 | Oracle 绑定变量

    之前整理过一篇有关绑定变量的文章,不太详细,重新补充一下. Oracle 绑定变量 http://www.cndba.cn/Dave/article/1275 一.绑定变量 bind variable ...

  3. Oracle绑定变量

    select * from table where id = ? 类似于上面这样的sql,如果不用绑定变量,每次执行时Oracle会认为是不同的sql,会在每次执行时生成一遍执行计划,而执行计划的生成 ...

  4. [转]ORACLE 绑定变量用法总结

    转:http://blog.csdn.net/wanghai__/article/details/4778343 在oracle 中,对于一个提交的sql语句,存在两种可选的解析过程, 一种叫做硬解析 ...

  5. oracle 绑定变量

    “绑定变量”这个词也许对于某些人来说看以来陌生,其实我们在很早的时候就已经开始运用它了. 在java中使用的PrepareStatement对象,大家一定会说这不是将sql语句做预编译操作嘛,被封装的 ...

  6. ORACLE 绑定变量用法总结 .

    之前对ORACLE中的变量一直没个太清楚的认识,比如说使用:.&.&&.DEIFINE.VARIABLE……等等.今天正好闲下来,上网搜了搜相关的文章,汇总了一下,贴在这里,方 ...

  7. Oracle绑定变量优缺点

    参考:http://f.dataguru.cn/thread-208881-1-1.html 参考:http://blog.sina.com.cn/s/blog_4d9ece9a0100caw8.ht ...

  8. Oracle绑定变量在C#.NET中的应用及意义

    一. 什么是绑定变量 绑定变量(bind variable) : select * from emp where empno=:empno; 是用户放入查询中的占位符,它会告诉Oracle“我会随后为 ...

  9. oracle绑定变量测试及性能对比

    1.创建测试数据 2.查看cursor_sharing的值 SQL> show parameter cursor_sharing; NAME TYPE VALUE --------------- ...

随机推荐

  1. docker 实践十:docker 网络管理

    本篇是关于 docker 网络管理的内容,同时也包含了 docker 网络的高级应用. 注:环境为 CentOS7,docker 19.03. docker 网络基础 docker 网络模型 在 do ...

  2. Luogu5405 CTS2019氪金手游(容斥原理+树形dp)

    考虑外向树怎么做.显然设f[i][j]为i子树中出现权值和为j的合法方案的概率,转移做树形背包即可. 如果树上只有一条反向边,显然可以先不考虑该边计算概率,再减去将整棵树看做外向树的概率.于是考虑容斥 ...

  3. oracle 的分页、截断查询

    oracle 分页.截断查询 需求:从车管所的备案库中(oracle)取出数据,放到车综大数据平台(http方式) 现场情况:oracle中有三张表,CZRKXX(常住人口信息),ZDRYXX(重点人 ...

  4. SDL 实现多线程 的一些BUG

    1. SDL_init()  在多个线程初始化的时候  , 在第二个线程出现SDL_init 崩溃的现象  SDL init  错误码:0XFFFFFFFF 2. SDL_init() 如果只初始化一 ...

  5. 基于SCADA数据驱动的风电机组部件故障预警

    吴亚联 1 , 梁坤鑫 1 , 苏永新 1* , 詹 俊 2(1.湘潭大学 信息工程学院, 湖南 湘潭 411105: 2.湖南优利泰克自动化系统有限公司, 湖南 长沙 410205) 摘 要: 为提 ...

  6. Node.js 实战(一)之—防灾备措施

    前言 博客系统上线已经3个多月了,中间没有出现过宕机事故,一直稳定运行.自己写的代码还是挺严谨的,小小鼓励一下!上周对云服务器进行了一次内存扩容,扩容后重启了一次服务器.虽然过程很短,但是因重启后导致 ...

  7. node.js 微信开发2-消息回复、token获取、自定义菜单

    项目结构 >config/wechat.json 微信公众号的配置文件 >controllers/oauth.js 微信网页授权接口(下一篇再细讲讲) >controllers/we ...

  8. 记录java+testng运行selenium(二)---定义元素类及浏览器

    一: 元素类 整体思路: 1. 根据状态可分可见和不可见两种 2. 同一个路径可以查找单个元素或多个元素 3. 获取元素text或者指定的value值 4. selenium对元素操作有两种,一是通过 ...

  9. Linux命令——ldd和ldconfig

    转自:Linux系统中“动态库”和“静态库”那点事儿 前言 在调试lua脚本的时候,报错. 我已经再lua脚本中更改了cpath package.cpath = package.cpath .. &q ...

  10. Spring Cloud 之 服务网关

    在微服务架构体系中,使用API 服务网关后的系统架构图如下: API服务网关的主要作用如下: 服务访问的统一入口 服务访问的负载均衡功能 服务访问的路由功能 在SpringCloud中,基于Netfl ...