在 1.3 节中提到,执行计划中的 Rows 是假的,是 CBO 根据统计信息和数学公式估算出来的,所以在看执行计划的时候,一定要注意嵌套循环驱动表的 Rows 是否估算准确,同时也要注意执行计划的入口 Rows 是否算错。因为一旦嵌套循环驱动表的 Rows 估算错误,执行计划就错了。如果执行计划的入口 Rows 估算错误,那执行计划也就不用看了,后面全错

    现有如下执行计划。

    1. select * from table(dbms_xplan.display);
    1. PLAN_TABLE_OUTPUT
    2. -------------------------------------------------------------------------------------
    3. Plan hash value: 3215660883
    4. -------------------------------------------------------------------------------------
    5. | Id |Operation |Name |Rows | Bytes | Cost(%CPU)|
    6. -------------------------------------------------------------------------------------
    7. | 0 |SELECT STATEMENT | | 78| 4212 | 15507 (1)|
    8. | 1 | HASH GROUP BY | | 78| 4212 | 15507 (1)|
    9. | 2 | NESTED LOOPS | | | | |
    10. | 3 | NESTED LOOPS | | 3034| 159K| 15506 (1)|
    11. |* 4 | TABLE ACCESS FULL |OPT_REF_UOM_TEMP_SDIM| 2967| 101K| 650 (14)|
    12. |* 5 | INDEX RANGE SCAN |PROD_DIM_PK | 3| | 2 (0)|
    13. |* 6 | TABLE ACCESS BY INDEX ROWID|PROD_DIM | 1| 19 | 5 (0)|
    14. -------------------------------------------------------------------------------------
    15. Predicate Information (identified by operation id):
    16. ---------------------------------------------------
    17. 4 - filter("UOM"."RELTV_CURR_QTY"=1)
    18. 5 - access("PROD"."PROD_SKID"="UOM"."PROD_SKID")
    19. 6 - filter("PROD"."BUOM_CURR_SKID" IS NOT NULL AND "PROD"."PROD_END_DATE"=TO_DATE('
    20. 9999-12-31 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "PROD"."CURR_IND"='Y' AND
    21. "PROD"."BUOM_CURR_SKID"="UOM"."UOM_SKID")
    22. 22 rows selected.

    执行计划中 Id=4 是嵌套循环的驱动表,同时也是执行计划的入口,CBO 估算它只返回 2 967 行数据。Id=4 前面有「*」号,表示有谓词过滤4 - filter("UOM"."RELTV_CURR_QTY"=1)

    根据执行计划中 Id=4 的谓词信息,手动计算 Id=4 应该返回真正的 Rows 如下。

    1. select count(*) from OPT_REF_UOM_TEMP_SDIM where "RELTV_CURR_QTY"=1;
    1. COUNT(*)
    2. ----------
    3. 946432

    手动计算出的 Rows 返回了 946 432 行数据,与执行计划中的 2 967 行相差巨大,所以本示例中,执行计划是错误的。