绑定感知光标匹配说明

时间:2014-03-18 22:24:26

标签: database oracle bind sqlplus bind-variables

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

1 个答案:

答案 0 :(得分:5)

在最简单的情况下,假设您有一个ORDERS表。该表中包含status列。只有少数status值,有些非常非常受欢迎,而其他非常罕见。想象一下,该表有1000万行。为了我们的目的,比如93%是" COMPLETE",5%" CANCELED",剩下的2%分布在跟踪订单流的8种不同状态之间(INCOMPLETE,完成,完成,过境等)。

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

这样的查询时
SELECT *
  FROM orders
 WHERE status = :1

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

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

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

SELECT *
  FROM orders
 WHERE status = 'IN TRANSIT'

VS

SELECT *
  FROM orders
 WHERE status = 'COMPLETED'

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

Oracle的第一个解决方案被称为"绑定变量偷看"。在这种方法中,当优化器看到像

这样的东西时
SELECT *
  FROM orders
 WHERE status = :1

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

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

但绑定变量偷看在其他情况下效果不佳。如果您的系统中应用程序有时会绑定非常流行的值并且有时会绑定非常罕见的值,那么最终会出现这样的情况,即应用程序性能在很大程度上取决于首先运行查询的人员。如果运行查询的第一个人使用非常罕见的值,则将生成并缓存索引扫描计划。如果运行查询的第二个人使用非常常见的值,则将使用缓存的计划,并且您将获得永远需要的索引扫描。如果角色被颠倒,第二个人使用稀有值,获得执行全表扫描的缓存计划,并且必须扫描整个表以获得他们感兴趣的几百行。这种非-deterministic行为倾向于驱使DBA和开发人员疯狂,因为它可能很难诊断并且可能导致相当奇怪的解释 - Tom Kyte有一个很好的例子,客户得出结论they needed reboot the database in the afternoon if it rained Monday morning

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

SELECT *
  FROM orders
 WHERE status = :1

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

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