日期:2014-05-16 浏览次数:20508 次
通过索引来访问表的成本公式应该包含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,可以