日期:2014-05-16 浏览次数:20395 次
通过索引来访问表的成本公式应该包含3个与块相关的组件:按降序遍历的分支层数、遍历 叶块的数目和访问过的表块的数目。
1、入门
SQL> create table t1 2 nologging 3 as 4 select 5 trunc(dbms_random.value(0,25))n1, --n1会产生25个不同的值。 6 rpad('x',40)ind_pad, --只有一个值。 7 trunc(dbms_random.value(0,20))n2, --n2会产生20个不同的值。 8 lpad(rownum,10,'0')small_vc, 9 rpad('x',200)padding 10 from 11 all_objects 12 where rownum <= 10000 14 ; 表已创建。 SQL> create index t1_i1 on t1(n1, ind_pad, n2) 2 nologging 3 pctfree 91 4 ; 索引已创建。 SQL> begin 2 dbms_stats.gather_table_stats( 3 user, 4 't1', 5 cascade => true, 6 estimate_percent => null, 7 method_opt => 'for all columns size 1' 8 ); 9 end; 10 / PL/SQL 过程已成功完成。
SQL> select t.TABLE_NAME, t.NUM_ROWS, t.BLOCKS 2 from user_tables t 3 where table_name = 'T1'; TABLE_NAME NUM_ROWS BLOCKS ------------------------------ ---------- ---------- T1 10000 387 SQL> select s.table_name, 2 s.column_name, 3 s.num_distinct, 4 s.density, 5 s.num_nulls, 6 s.avg_col_len 7 from user_tab_col_statistics s 8 where table_name = 'T1'; TABLE_NAME COLUMN_NAME NUM_DISTINCT DENSITY NUM_NULLS AVG_COL_LEN ------------------------------ ------------------------------ ------------ ---------- ---------- ----------- T1 N1 25 .04 0 3 T1 IND_PAD 1 1 0 41 T1 N2 20 .05 0 3 T1 SMALL_VC 10000 .0001 0 11 T1 PADDING 1 1 0 201 SQL> select i.index_name, 2 i.table_name, 3 i.blevel, 4 i.leaf_blocks, 5 i.distinct_keys, 6 i.clustering_factor, 7 i.num_rows 8 from user_indexes i 9 where index_name = 'T1_I1'; INDEX_NAME TABLE_NAME BLEVEL LEAF_BLOCKS DISTINCT_KEYS CLUSTERING_FACTOR NUM_ROWS ------------------------------ ------------------------------ ---------- ----------- ------------- ----------------- ---------- T1_I1 T1 2 1111 500 9752 10000
可以看见DISTINCT_KEYS等于索引列的NUM_DISTINCT相乘 = 25 * 1 * 20 = 500。一共有500种组合,没种组合对应的行数就是20行(10000 / 500 = 20)。
SQL> select small_vc 2 from t1 3 where n1 = 2 4 and ind_pad = rpad('x', 40) 5 and n2 = 3; 执行计划 ---------------------- Plan hash value: 1429545322 ------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------- | 0 | SELECT STATEMENT | | 20 | 1160 | 25 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| T1 | 20 | 1160 | 25 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | T1_I1 | 20 | | 5 (0)| 00:00:01 | ------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("N1"=2 AND "IND_PAD"='x ' AND "N2"=3)
索引选择率:n1选择率*ind_pad选择率*n2选择率=1/25 * 1 * 1/20 = 1/500 = 1 / DISTINCT_KEYS
返回基数:1 / DISTINCT_KEYS * NUM_ROWS = 1/500 * 10000 = 20。
通过索引查询的成本为25,基数为20。基数估算非常准确,但成本又是如何得出的呐?CBO认为一共读取了20行数据,对访问表的成本为20不应该感到惊奇。索引的成本是5,可以