在 1.3 节中提到,执行计划中的 Rows 是假的,是 CBO 根据统计信息和数学公式估算出来的,所以在看执行计划的时候,一定要注意嵌套循环驱动表的 Rows 是否估算准确,同时也要注意执行计划的入口 Rows 是否算错。因为一旦嵌套循环驱动表的 Rows 估算错误,执行计划就错了。如果执行计划的入口 Rows 估算错误,那执行计划也就不用看了,后面全错。
现有如下执行计划。
select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------
Plan hash value: 3215660883
-------------------------------------------------------------------------------------
| Id |Operation |Name |Rows | Bytes | Cost(%CPU)|
-------------------------------------------------------------------------------------
| 0 |SELECT STATEMENT | | 78| 4212 | 15507 (1)|
| 1 | HASH GROUP BY | | 78| 4212 | 15507 (1)|
| 2 | NESTED LOOPS | | | | |
| 3 | NESTED LOOPS | | 3034| 159K| 15506 (1)|
|* 4 | TABLE ACCESS FULL |OPT_REF_UOM_TEMP_SDIM| 2967| 101K| 650 (14)|
|* 5 | INDEX RANGE SCAN |PROD_DIM_PK | 3| | 2 (0)|
|* 6 | TABLE ACCESS BY INDEX ROWID|PROD_DIM | 1| 19 | 5 (0)|
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter("UOM"."RELTV_CURR_QTY"=1)
5 - access("PROD"."PROD_SKID"="UOM"."PROD_SKID")
6 - filter("PROD"."BUOM_CURR_SKID" IS NOT NULL AND "PROD"."PROD_END_DATE"=TO_DATE('
9999-12-31 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "PROD"."CURR_IND"='Y' AND
"PROD"."BUOM_CURR_SKID"="UOM"."UOM_SKID")
22 rows selected.
执行计划中 Id=4 是嵌套循环的驱动表,同时也是执行计划的入口,CBO 估算它只返回 2 967 行数据。Id=4 前面有「*」号,表示有谓词过滤4 - filter("UOM"."RELTV_CURR_QTY"=1)
。
根据执行计划中 Id=4 的谓词信息,手动计算 Id=4 应该返回真正的 Rows 如下。
select count(*) from OPT_REF_UOM_TEMP_SDIM where "RELTV_CURR_QTY"=1;
COUNT(*)
----------
946432
手动计算出的 Rows 返回了 946 432 行数据,与执行计划中的 2 967 行相差巨大,所以本示例中,执行计划是错误的。