CBO基于成本的优化器改变了SQL执行过程中的对谓词选择性的评估方式,使得执行计划更加合理,这种评估是以列的选择性为基础,在数据均匀分布的情况下没有问题,如果数据存在倾斜,通过绑定变量传入的值会导致走错误的执行计划,在9i中,引入"Bind Peeking"以试图解决与绑定变量的选择性相关的问题,初始的绑定值与后续传入的绑定值具有不同的选择性时计划可能只使用第一次硬解析生成的计划。10g时默认的统计数据收集方法更改为自动收集直方图加剧了这一问题,10g前基于不同值的数量生成的选择性现在是基于直方图生成的。为解决该问题,在Oracle 11g 中,引入了自适应游标共享,自适应游标共享监视候选查询的执行统计信息,并使同一查询可以为不同的绑定值生成和使用不同的执行计划。

The adaptive cursor sharing feature enables a single statement that contains bind variables to use multiple execution plans. Cursor sharing is "adaptive" because the cursor adapts its behavior so that the database does not always use the same plan for each execution or bind variable value.

自适应游标共享主要涉及三个字段:is_bind_sensitive,is_bind_aware,is_shareable,含义如下:

is_bind_sensitive

绑定是否敏感,表示该子游标中是否使用了绑定变量要素,且采用bind peeking方法进行执行计划生成。如果执行计划依赖于窥探到的值,此处为Y,否则为N。
在以下情况下,游标被标记为绑定敏感:
  • 使用绑定窥视执行查询
  • 使用以下任何关系运算符进行绑定 = < > <= >= != 或用户定义的绑定运算符,例如 contains(e.job,:job,1)>0,
  • 从 11.2.0.2 开始,还支持“LIKE”运算符.
  • 直方图存在于包含绑定值的列上。

换句话说,如果绑定变量值的更改可能导致不同的计划,则将游标标记为绑定敏感。
绑定敏感除了要求满足有效的运算符之外,还需要满足以下绑定敏感性检查,检查中的任何一个失败,则游标将不会被标记为绑定敏感且不会进行自适应游标共享,同时将禁用自适应游标共享:

  • 扩展游标共享已被禁用
  • 未使用绑定变量
  • 并行查询
  • 设置了某些参数,例如 ("_optim_peek_user_binds"=false)
  • 使用 /*+ NO_BIND_AWARE */ 提示
  • 正在使用大纲
  • 递归查询
  • 绑定变量数大于14。

游标被标记为绑定敏感时,会创建并存储有关游标执行统计信息的“共享上下文”信息,可以通过在V$SQL或V$SQLAREA中IS_BIND_SENSITIVE 列为Y的值进行判断。
如果在连续执行中执行相同 sql 语句的行源基数存在显着变化,则游标将被标记为绑定感知。这将允许为不同的绑定选择性值创建多个子游标,同时在可能的情况下仍尝试共享子游标。

IS_BIND_AWARE

绑定是否感知
表示该子游标是否使用了extended cursor sharing技术,是则为Y,否则为N,如为N,则该游标将废弃,不再可用。对不同的绑定值使用不同的计划。在使游标成为绑定感知之后,优化器会根据绑定值及其选择性估计来选择未来执行的计划。当带有绑定敏感游标的语句执行时,数据库决定是否将游标标记为绑定感知。该决定取决于游标是否为不同的绑定值产生显着不同的数据访问模式。如果数据库将游标标记为绑定感知,则下次游标执行时数据库会执行以下操作:

  • 根据新的绑定值生成新计划。
  • 将为语句生成的原始游标标记为不可共享 ( V$SQL.IS_SHAREABLEis N)。此游标不再可用,将成为第一个从共享 SQL 区域中老化的游

is_shareable

是否可共享
表示该子游标可否被下次软解析是否可共享使用。可共享则为Y,否则为N,表示该子游标失去了共享价值,按LRU算法淘汰。

监控


V$SQL 可用于查看游标是is_bind_sensitive、is_bind_aware 还是is_shareable。

如果SQL语句为首次执行,因此从v$sql查询的结果中得知

is_bind_sensitive 为Y值(首次运行,执行了bind peeking)

is_bind_aware 为N值(首次运行,不被extended cursor sharing支持)

is_shareable 为Y值(执行计划可共享)



绑定上下文信息可以通过 V$SQL_CS_SELECTIVITY、V$SQL_CS_STATISTICS 和 V$SQL_CS_HISTOGRAM 查看


V$SQL_CS_SELECTIVITY 在扩展游标共享模式下显示子游标的有效选择性范围。
有效范围由包含绑定的每个谓词的低值和高值组成。每个谓词的选择性(与当前绑定值)必须介于相应的低值和高值之间,以便共享子游标。


V$SQL_CS_STATISTICS 包含自适应游标共享的监视组件使用的原始执行统计信息。
监视执行的样本。这个视图显示了哪些执行被采样,以及这些执行的统计数据是什么。对于每组不同的绑定值,统计信息是累积的。


V$SQL_CS_HISTOGRAM 汇总了自适应游标共享存储的监控信息。
此信息用于决定是否为查询启用扩展游标共享。存储在直方图中。

缺陷

ACS可能导致大量的子游标生成,占用共享池并伴随大量的mutex X等待。
Checklist to avoid known issues
  1. Ensure that cursor_sharing is not set to SIMILAR. In 11g this setting is not recommended and is deprecated in future releases.

Document 1169017.1:ANNOUNCEMENT: Deprecating the cursor_sharing = 'SIMILAR' setting

  1. If there are high version counts check v$sql_shared_cursor and search My Oracle Support for notes that may allude to the cause of the excessive cursors.

Document 438755.1 : Formated V$SQL_SHARED_CURSOR Report by SQLID or Hash Value
If there are still excessive child cursors, then Oracle Support should be contacted to assist with diagnosing the issue.

  1. Bug 10182051 has a query with many predicates containing binds has many shareable child cursors (is_shareable = 'Y' in V$SQL) with the same plan hash value, but some with other plan hash values:

Document 10182051.8 EXTENDED CURSOR SHARING GENERATES 100S OF SHAREABLE CHILD CURSORS FOR A QUERY

Known Issues

  1. Bug 8357294 is where adaptive cursor sharing will not work from PL/SQL. This is currently being worked on:

Bug 8357294 ADAPTIVE CURSOR SHARING DOESN'T WORK FOR STATIC SQL CURSORS FROM PL/SQL

  1. Extra memory consumption may be seen per cursor in the shared pool when adaptive cursor sharing is enabled due to following bug:

Bug 14033503 : EXCESSIVE MEMORY CONSUMPTION FOR ADAPTIVE CURSOR SHARING