绑定感知光标匹配说明

bda*_*086 2 database oracle bind sqlplus bind-variables

嗨我在尝试找到oracle中绑定感知游标匹配的简单解释时遇到了一些麻烦.绑定感知游标匹配基本上是Oracle监视带有绑定变量的查询随着时间的推移并查看使用时是否有增加的CPU变量.然后从这样做它几乎生成一个更合适的执行计划,然后说全表扫描然后将查询标记为绑定意识,然后在下次执行查询时,可以选择两个执行计划?任何帮助将不胜感激!干杯!

Jus*_*ave 5

在最简单的情况下,假设你有一张ORDERS桌子.在该表中是一status列.只有极少status数值,有些非常非常受欢迎,有些非常罕见.想象一下,该表有1000万行.出于我们的目的,假设93%是"完全",5%是"取消",剩下的2%分布在跟踪订单流的8种不同状态之间(不完整,完整,完成,在运输等). ).

如果您的表具有最基本的统计信息,则优化程序会知道有1000万行和10种不同的状态.它不知道某些status值比其他值更受欢迎,因此它猜测每个状态对应于100万行.所以当它看到像这样的查询时

SELECT *
  FROM orders
 WHERE status = :1
Run Code Online (Sandbox Code Playgroud)

它猜测它需要从表中获取100万行,而不管绑定变量值如何,因此它决定使用全表扫描.

现在,人们开始想知道为什么甲骨文是愚蠢的并且当他要求少数orders处于IN TRANSIT状态时进行全表扫描- 显然索引扫描在那里会更好.人类意识到优化器需要更多信息才能知道某些status值比其他值更受欢迎,因此人类决定收集直方图(有些选项会导致Oracle自动收集某些列上的直方图,但我忽略了试图让故事变得简单的那些选项).

一旦收集了直方图,优化器就会知道该status值是高度倾斜的 - 有很多COMPLETED订单,但IN TRANSIT订单很少.如果它看到一个使用文字而不是绑定变量的查询,即

SELECT *
  FROM orders
 WHERE status = 'IN TRANSIT'
Run Code Online (Sandbox Code Playgroud)

VS

SELECT *
  FROM orders
 WHERE status = 'COMPLETED'
Run Code Online (Sandbox Code Playgroud)

那么优化器很容易决定在第一种情况下使用索引,在第二种情况下使用表扫描.但是,当你有一个绑定变量时,优化器的工作就更难了 - 它应该如何确定是使用索引还是进行表扫描......

Oracle的第一个解决方案被称为"绑定变量偷看".在这种方法中,当优化器看到类似的东西时

SELECT *
  FROM orders
 WHERE status = :1
Run Code Online (Sandbox Code Playgroud)

它知道(由于直方图status)查询计划应该依赖于传递给绑定变量的值,Oracle在传递的第一个值"偷看"以确定如何优化语句.如果第一个绑定变量值为"IN TRANSIT",则将使用索引扫描.如果第一个绑定变量值为"COMPLETE",则将使用表扫描.

对于很多情况,这非常有效.很多查询真的只对非常流行或非常罕见的值有意义.在我们的例子中,任何人都不太可能真的想要所有900万个COMPLETE订单的列表,但有人可能想要在一个不同的暂时状态中列出几千个订单.

但绑定变量偷看在其他情况下不能很好地工作.如果您的系统中应用程序有时会绑定非常流行的值并且有时会绑定非常罕见的值,那么最终会出现这样的情况:应用程序性能在很大程度上取决于首先运行查询的人员.如果运行查询的第一个人使用非常罕见的值,则将生成并缓存索引扫描计划.如果运行查询的第二个人使用非常常见的值,则将使用缓存的计划,并且您将获得永远需要的索引扫描.如果角色被颠倒,第二个人使用罕见值,获取执行全表扫描的缓存计划,并且必须扫描整个表以获得他们感兴趣的几百行.这种非确定性行为倾向于驱使DBA和开发人员疯狂,因为它可能很难诊断,并且可能导致相当奇怪的解释 - Tom Kyte有一个很好的客户示例,他们认为如果周一早上下雨,他们需要在下午重新启动数据库.

绑定感知游标匹配是绑定变量偷看问题的解决方案.现在,当Oracle看到查询时

SELECT *
  FROM orders
 WHERE status = :1
Run Code Online (Sandbox Code Playgroud)

并且看到有一个直方图status表明某些值比其他值更常见,它足够智能使该游标"绑定感知".这意味着当您绑定IN FULFILLMENT的值时,优化器足够聪明,可以断定这是一个罕见的值,并为您提供索引计划.绑定COMPLETE值时,优化器足够聪明,可以断定这是常用值之一,并为计划提供表扫描.因此,优化器现在知道同一查询的两个不同计划,当它看到像IN TRANSIT这样的新绑定值时,它会检查该值是否与之前看到的其他值类似,并且为您提供现有计划之一或创建另一个新计划.在这种情况下,它将决定IN TRANSIT与IN FULFILLMENT大致相同,因此它会使用索引扫描重新使用该计划,而不是生成第三个查询计划.希望这可以使每个人都获得他们的首选计划,而无需在每次绑定变量值更改时生成和缓存查询计划.

当然,实际上,还有很多额外的警告,角落案例,考虑因素和并发症,我有意(无意间)在这里进行了修饰.但这是优化器试图完成的基本思路.