我们通过以下查询语句来演示索引范围扫描和由索引 ROWID 访问表操作的代价估算:

通过 PLAN_TABLE 还能获得由优化器估算出的 IO 代价和 CPU 指令数:

获得基本数据
o 获取相关系统参数设置

索引代价调节比(OPTICA)为 60。优化器采用的数据块大小(OPTBLKSIZE)为 8192。并且未启用缓存统计数据。
o 获取索相关引统计数据

索引 T_OBJECTS_IDX1 的 B 树高度(BLVL)为 2,叶子节点数(LBLKS)为 209,簇集因子(CLUF) 为 32050,索引记录数(INDROWS)为 47585。
o 获取索引中的字段信息

以上结果可知该索引建立在 T_OBJECTS(STATUS, OWNER, OBJECT_NAME) 上。
o 获取相关字段的数据类型及在表中位置
根据计算公式,相关字段包括选择字段、索引字段和谓词条件字段。

o 选择率计算
在查询中,包括了五个谓词条件:

它们分别组成了索引访问条件、索引过滤条件和表过滤条件。

我们先按照之前给出的选择率计算方法,结合他们的统计数据及绑定变量值,计算出它们的选择率(过程和前面章节类似,略):
按照由底向上的原则,先计算索引范围扫描的代价。
索引范围扫描代价计算
分别按照上节给出的计算公式计算 IO 代价和 CPU 代价。
o IO 代价
根据公式,我们需要计算出索引访问条件(“STATUS”=‘VALID’ AND “OWNER”>‘DEMO’)的选择率: INDACCSEL = OPSEL[status] * OPSEL[owner]
= 0.9927669*0.9789120
= 0.971831
并将查询得到的统计数据和系统参数设置数值代入公式,得到索引范围扫描的单数据块读数:
#SRDS = BLVL + CEIL(LBLKSINDACCSEL)
= 2 + CEIL(3090.971831)
= 303
考虑索引代价条件比,得到调整后的 IO 代价值:
IOCOST = ROUND(#SRDS * OPTICA/100)
= ROUND(303 * 60/100)
= 182
结果和执行计划中的估算值一致。
o CPU 代价
依据索引范围扫描的 CPU 总指令数计算公式,需要计算得到索引过滤 CPU 指令数(PICYCLES)。该执行计划中,索引过滤条件为(“OWNER”<>‘SYS’ AND “OBJECT_NAME”<>‘TEST’),且字段 OWNER 也同时出现在了访问条件中,因此 PICYCLES 为:
PICYCLES = TYPOPCYCLES[object_name]+TYPOPCYCLES[owner]OPSEL[object_name]
= 50 + 500.9999661
= 99.998305
再将查询得到的数值代入计算公式得到未调节的 CPU 指令数:
#CPUCYCLES = ROUND(ROUND(#SRDS*(0.32OPTBLKSIZE + 3650 + 850)) + ROUND(#SRDSCACHEHIT850) + CEIL(INDROWSINDACCSEL)200 + ROUND(INDROWSINDACCSEL)PICYCLES)
= ROUND(ROUND(303(0.328192 + 3650 + 850)) + ROUND(3030850) + CEIL(475850.971831)200 + ROUND(475850.971831)*99.998305)
= 16031218
考虑索引代价条件比,得到调整后的 IO 代价值:
#CPUCYCLES = ROUND(16031218 * 60/100)
= 9618731
结果和执行计划中的估算值一致。
由索引 ROWID 访问表代价计算
分别按照上节给出的计算公式计算由索引 ROWID 访问表的 IO 代价和 CPU 代价。
o IO 代价
根据公式,我们需要计算出索引过滤条件的选择率:
INDFLTSEL = INDACCSEL * OPSEL[owner] * OPSEL[object_name]
= 0.9718310.51629990.9999661
= 0.501739
将计算数据和统计数据代入公式,得到单数据块读数:
#SRD= #SRDS[Index Scan] + #SRDS[Access Table]
= 303 + CEIL(32050*0.501739)
= 303 + 16081
= 16384
其中,16081 为访问表的单数据块读次数。
考虑索引代价条件比,得到调整后的 IO 代价值:
IOCOST = ROUND(#SRDS * OPTICA/100)
= ROUND(16384 * 60/100)
= 9830
结果和执行计划中的估算值一致。
o CPU 代价
依据索引范围扫描的 CPU 总指令数计算公式,需要计算得到表数据过滤 CPU 指令数
(FLTCYCLES)。该执行计划中,表数据过滤条件为"OBJECT_ID"<66666,因此 FLTCYCLES 为 50。在索引字段中,STATUS 的位置最大,为 10;选择字段中,SECONDARY 的位置最大,为 13;过
滤条件中,OBJECT_ID 位置最大,为 4.
将统计数据代入计算公式
#CPUCYCLES[Table Access] = ROUND(#SRDS*(0.32OPTBLKSIZE + 3650 + 850)) + ROUND(#SRDSCACHEHIT850) + CEIL(INDROWSINDFLTSEL)130 + CEIL(INDROWSINDFLTSEL)GREATEST(MAXINDCPOS, MAXSELCPOS, MAXFLTCPOS)20 + CEIL(INDROWSINDFLTSELFLTCYCLES)
= ROUND(16081*(0.328192 + 3650 + 850)) + ROUND(160810850) + CEIL(475850.501739)130 + CEIL(475850.501739)GREATEST(10, 13, 4)20 + CEIL(475850.50173950)
= 125025280
加上索引范围扫描的 CPU 指令数,得到当前操作的 CPU 指令数:
#CPUCYCLES = #CPUCYCLES[Table Access] + #CPUCYCLES[Index Scan]
= 16031218 + 125025280
= 141056498
考虑索引代价条件比,得到调整后的 IO 代价值:
#CPUCYCLES = ROUND(#CPUCYCLES * OPTICA/100)
= ROUND(141056498 * 60/100)
= 84633899
o 总代价
结果和执行计划中的估算值一致。在考虑系统统计参数 CPUSPEED(1974.735)和 SREADTIM
(10.381),可以计算的最终代价值。
COST = IOCOST + CPUCOST
= ROUND(16384 * 60/100 + #CPUCYCLES * 60/100 / (CPUSPEED1000SREADTIM))
= 9830.4 + 4.1285
= 9835.5285
实际结果
以下为该例的实际代价结果,与我们的计算结果基本吻合:

读者可以参考上例的优化器跟踪文件“06_92_10053_IRS(T_OBJECTS_IDX1)_DEMO.trc”。




