optimizer_index_cost_adj 初始化参数用于改变通过索引扫描的表访问的成本。合法的值为从1到10000。默认值是100。大于100的值会使索引扫描成本更加高昂并因此倾向于全表扫描。小于100的值会使索引扫描的成本降低。
要理解这个初始化参数对于成本公式的影响,描述查询优化器如何计算与基于索引范围扫描的表访问有关的成本会很有帮助。
索引范围扫描是对多个键值的索引查找。如图9-4所示,执行的操作如下。
(1)访问索引的根块。
(2)遍历分支块来定位包含第一个键值的叶子块。
(3)对于每一个满足搜索条件的键值,执行以下操作:
a.提取引用数据块的rowid;
b.访问由rowid引用的数据块。
一次索引范围扫描执行的物理读数量等于定位包含第一个键值的叶子块所访问的分支块的数量(也就是blevel统计信息),加上扫描的叶子块数量(leaf_blocks统计信息乘以操作的选择率),再加上通过rowid访问的数据块数量(clustering_factor统计信息乘以操作的选择率)。这样就得到了公式9-3,此外,合并考虑了optimizer_index_cost_adj初始化参数应用的修正。
公式9-3基于索引范围扫描的表访问的I/O成本
注意 在公式9-3中,相同的选择率被同时应用于计算索引访问的成本(图9-4中的3a操作)和表访问的成本(3b操作)。在现实中,查询优化器可能会为这两个成本计算使用两个不同的选择率。当只有一部分过滤条件是通过索引访问实施的时候,才有必要这样做。例如,当一个索引由三个列组成而第二个列上没有限制条件时,就会出现这种情况。
概括起来,你可以看到optimizer_index_cost_adj初始化参数对索引访问的I/O成本有着直接的影响。将它设置为一个比默认值小的值时,所有的成本成比例下降。在某些情况下这可能是个问题,因为查询优化器会对其估算的结果进行舍入操作。这就意味着,即使一些索引的对象统计信息是不同的,但是从查询优化器的角度来看它们可能都拥有一样的成本。
如果几个成本数值上相等,查询优化器则根据索引的名称决定使用哪一个!它直接按字母顺序选择第一个。在接下来的例子中将演示这个问题。注意当optimizer_index_cost_adj初始化参数和索引名称发生变化时,INDEX RANGE SCAN操作使用的索引是如何变化的。下面是对optimizer_index_cost_adj.sql脚本生成输出的一段摘录:
P257
ALTER SESSION SET
OPTIMIZER_INDEX_COST_ADJ=100;
EXPLAIN PLAN FOR
SELECT * FROM t WHERE val1 = 11 AND val2 =
11;
SELECT * FROM table(dbms_xplan.display);
ALTER SESSION SET
OPTIMIZER_INDEX_COST_ADJ=10;
EXPLAIN PLAN FOR
SELECT * FROM t WHERE val1 = 11 AND val2 =
11;
SELECT * FROM table(dbms_xplan.display);
ALTER INDEX t_val1_i RENAME TO t_val3_i;
EXPLAIN PLAN FOR
SELECT * FROM t WHERE val1 = 11 AND val2 =
11;
SELECT * FROM table(dbms_xplan.display);
要避免这种不稳定性,通常我不推荐将optimizer_index_cost_adj初始化参数设置为较低的值。
同样重要的是,系统统计信息提供与全表范围扫描相关的成本的修正。这就是说,如果系统统计信息就位,默认值通常会表现良好。还要注意系统统计信息没有这个参数所拥有的缺点,因为系统统计信息是增加成本而非降低成本。
optimizer_index_cost_adj初始化参数是动态的,并且可以在实例和会话级别修改。在12.1版本的多租户环境下,也可以在PDB级别设置它。