且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

一次ORACLE SQL谓词跨界导致的执行计划不准

更新时间:2022-08-20 21:36:33

一次ORACLE SQL谓词跨界导致的执行计划不准


首先说明谓词跨界一般出现在日期类型中,打个比方你的统计数据是8月20号的,但是今天是8月28日,在这20号到28号之间日期是没有进入统计数据的,
这样可能导致,根据统计信息计算出来的COST异常的小,这样可能导致本来该走其他字段索引的语句走到时间索引上去,导致执行计划最终错误。
在10053中可以看到如下提示:


as selectvity of out-of-range/non-existent value pred


以前多次遇到过,今天再次遇到,就记录于此,如下SQL
select *
from test
where seller_user_id = '123'
and raw_add_time >= trunc(sysdate-1, 'mi')
and raw_add_time < trunc(sysdate, 'mi')


其执行计算如下:
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2023568823
--------------------------------------------------------------------------------
| Id  | Operation                    | Name                   | Rows  | Bytes |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                        |     1 |   574 |
|*  1 |  FILTER                      |                        |       |       |
|*  2 |   TABLE ACCESS BY INDEX ROWID| TEST                   |     1 |   574 |
|*  3 |    INDEX RANGE SCAN          | TEST_ADD_TIME_INDEX    |     2 |       |
--------------------------------------------------------------------------------
这里test_ADD_TIME_INDEX就是我的时间上的索引,通过查看选择率后发现seller_user_id远远
小于raw_add_time范围的选择率,应该走到seller_user_id上的索引才对,这里可能发生了
谓词跨界查看其统计数据发现是7月20号的,今天是8月28日。然后进行了一下验证


调整时间后
select *
from test
where seller_user_id = '123'
and raw_add_time >= trunc(sysdate-100, 'mi')
and raw_add_time < trunc(sysdate-99, 'mi')




PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 576270446
--------------------------------------------------------------------------------
| Id  | Operation                    | Name                 | Rows  | Bytes | Cos
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                      |     1 |   574 |
|*  1 |  FILTER                      |                      |       |       |
|*  2 |   TABLE ACCESS BY INDEX ROWID| TEST_BASE_INFO       |     1 |   574 |
|*  3 |    INDEX RANGE SCAN          | TEST_ID_INDEX |    23 |       |
--------------------------------------------------------------------------------


这里更改了时间范围在已知的统计数据范围内,执行计划正确。


我们进行10053 TRACE验证:


SINGLE TABLE ACCESS PATH 
  Single Table Cardinality Estimation for TEST[TEST] 
  Column (#14): 
    NewDensity:0.000001, OldDensity:0.000623 BktCnt:254, PopBktCnt:79, PopValCnt:7, NDV:814912
  Column (#14): SELLER_USER_ID(
    AvgLen: 21 NDV: 814912 Nulls: 855565 Density: 0.000001
    Histogram: HtBal  #Bkts: 254  UncompBkts: 254  EndPtVals: 183


  Column (#41): RAW_ADD_TIME(
    AvgLen: 8 NDV: 13533184 Nulls: 0 Density: 0.000000 Min: 2454768 Max: 2457225
  Using prorated density: 0.000000 of col #41 as selectvity of out-of-range/non-existent value pred //谓词跨界
  Table: TEST  Alias: TEST
    Card: Original: 27510606.000000  Rounded: 1  Computed: 0.00  Non Adjusted: 0.00
  Access Path: TableScan
    Cost:  618899.27  Resp: 618899.27  Degree: 0
      Cost_io: 616819.00  Cost_cpu: 43729541941
      Resp_io: 616819.00  Resp_cpu: 43729541941
  Using prorated density: 0.000000 of col #41 as selectvity of out-of-range/non-existent value pred //谓词跨界
  Access Path: index (RangeScan)
    Index: TEST_ADD_TIME_INDEX 
    resc_io: 5.00  resc_cpu: 39819
    ix_sel: 0.000000  ix_sel_with_filters: 0.000000 
    Cost: 5.00  Resp: 5.00  Degree: 1
 
 谓词跨界后选择率成为了0.000000,这样导致了执行计划错误。
 解决也很简单,按需求重新收集统计信息即可