三星索引概念:
第一颗星:与查询相关的索引行是相邻的,也就是where后面的等值谓词,可以匹配索引列顺序
第二颗星:索引行的顺序与查询语句需求一致,也就是order by 中的排序和索引顺序是否一致
第三颗星:索引行包含查询语句中所有的列
参考:《数据库索引设计与优化》
一、建立测试数据 SQL> create table id.cust(cno int,lname varchar(10),fname varchar(10),sex int,weight int,city varchar(10)); SQL> truncate table id.cust; SQL> declare i number; begin for i in 1..1000 loop insert into id.cust values(i, DBMS_RANDOM.STRING('u', 4), DBMS_RANDOM.STRING('u', 4),ABS(MOD(DBMS_RANDOM.RANDOM,2)),ABS(MOD(DBMS_RANDOM.RANDOM,150)),DBMS_RANDOM.STRING('u', 6)); commit; end loop; end; 二、三星索引测试 1、满足三星索引 --建立索引(三星) SQL> create index id.idx_cust on id.cust(city,lname,fname,cno); 对于下面的sql,建立如上就是三星索引: 第一颗星:所有等值谓词的列,把这些做组合索引的开头的列,如下sql的where条件的city,lname开头,顺序随意。 第二颗星:order by的字段加入组合索引中 fname字段(索引自动排序) 第三颗星:将查询中剩余的列加入组合索引中 select中的cno字段(fname之前已加入过) SQL> EXPLAIN PLAN FOR 2 select cno,fname 3 from id.cust 4 where lname = :1 5 and city = :2 6 order by fname; Explained. 这样建立索引后,执行计划最优,如下: SQL> select * from table(dbms_xplan.display); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Plan hash value: 3860859945 ----------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 34 | 2 (0)| 00:00:01 | |* 1 | INDEX RANGE SCAN| IDX_CUST | 1 | 34 | 2 (0)| 00:00:01 | ----------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- 1 - access("CITY"=:2 AND "LNAME"=:1) Note ----- - dynamic statistics used: dynamic sampling (level=2) 17 rows selected. 2、不满足三星索引 如果在where条件中,不满足第一颗星 等值谓词,那之前组合索引的顺序要更改 SQL> EXPLAIN PLAN FOR 2 select cno,fname 3 from id.cust 4 where lname between :lname1 and :lname2 5 and city = :2 6 order by fname; Explained. 执行计划有filter过滤,还有order by排序操作, 不满足第一颗星和第二颗星 SQL> select * from table(dbms_xplan.display); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Plan hash value: 1720078986 ------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 34 | 3 (34)| 00:00:01 | | 1 | SORT ORDER BY | | 1 | 34 | 3 (34)| 00:00:01 | |* 2 | FILTER | | | | | | |* 3 | INDEX RANGE SCAN| IDX_CUST | 1 | 34 | 2 (0)| 00:00:01 | ------------------------------------------------------------------------------- PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter(:LNAME2>=:LNAME1) 3 - access("CITY"=:2 AND "LNAME">=:LNAME1 AND "LNAME"<=:LNAME2) Note ----- - dynamic statistics used: dynamic sampling (level=2) 20 rows selected. 修改一下组合索引,让order by的列fname放在between谓词列lname之前,才能满足第二颗星,避免排序操作 SQL> drop index id.idx_cust ; Index dropped. SQL> create index id.idx_cust on id.cust(city,fname,lname,cno); Index created. SQL> EXPLAIN PLAN FOR 2 select cno,fname 3 from id.cust 4 where lname between :lname1 and :lname2 5 and city = :2 6 order by fname; Explained. 查看执行计划,没有了order by排序操作(索引自动排序) SQL> select * from table(dbms_xplan.display); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Plan hash value: 1083764640 ------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | 34 | 2 (0)| 00:00:01 | |* 1 | FILTER | | | | | | |* 2 | INDEX RANGE SCAN| IDX_CUST | 1 | 34 | 2 (0)| 00:00:01 | ------------------------------------------------------------------------------ Predicate Information (identified by operation id): PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- --------------------------------------------------- 1 - filter(:LNAME2>=:LNAME1) 2 - access("CITY"=:2 AND "LNAME">=:LNAME1 AND "LNAME"<=:LNAME2) filter("LNAME">=:LNAME1 AND "LNAME"<=:LNAME2) Note ----- - dynamic statistics used: dynamic sampling (level=2) 20 rows selected. 这里满足第三颗星,但第一 第二颗星只能二选一 避免排序 选择第二颗星 最窄索引片 选择第一颗星