★★ 组合索引的前导列与查询——ORACLE
2009-01-15 12:42
585 查看
组合索引的前导列与查询
url:http://hi.baidu.com/klkl1110/blog/item/46994526d6306704908f9d10.html
2009-01-05 19:36
url:http://hi.baidu.com/klkl1110/blog/item/46994526d6306704908f9d10.html
2009-01-05 19:36
关于组合索引的使用一直都存在着一些争议,记得在学OU的Performance Tuning时,讲师认为组合索引的使用存在着一定的局限,只有在谓词中出现全部索引列时才能使用效率最高的index unique scan, 否则谓词中必须包含前导列,否则会走Index full scan或者FTS。 kl@k02> create table te_emp as select * from hr.employees; Table created. kl@k02> create index emp_id1 on te_emp(employee_id,JOB_ID, department_id); Index created. kl@k02> create index emp_id2 on te_emp(salary); Index created. kl@k02> analyze table te_emp compute statistics for table for all columns for all indexes; Table analyzed. kl@k02> set autotrace traceonly exp; kl@k02> select employee_id,JOB_ID, department_id from te_emp; (不加谓词,走EMP_ID1的FULL SCAN) Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=107 Bytes=1391) 1 0 INDEX (FULL SCAN) OF 'EMP_ID1' (NON-UNIQUE) (Cost=1 Card=107 Bytes=1391) kl@k02> select employee_id,JOB_ID, department_id from te_emp where employee_id=9293; (加谓词前导列Employee_id时,走EMP_ID1 range scan) Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=13) 1 0 INDEX (RANGE SCAN) OF 'EMP_ID1' (NON-UNIQUE) (Cost=1 Card=1 Bytes=13) kl@k02> select employee_id,JOB_ID, department_id from te_emp where employee_id=1334 and JOB_ID=435 and department_id=273; (如谓词中包含全部索引列,走EMP_ID1 Range scan) Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=13) 1 0 INDEX (RANGE SCAN) OF 'EMP_ID1' (UNIQUE) (Cost=1 Card=1 Bytes=13) kl@k02> set autotrace off; kl@k02> select count(*) from (select distinct employee_id from te_emp); COUNT(*) ---------- 107 kl@k02> select count(*) from te_emp; COUNT(*) ---------- 107 kl@k02> create index emp_id3 on te_emp(employee_id); (此时创建一个单列索引emp_id3, 目前组合索引emp_id1仍然存在) Index created. kl@k02> analyze table te_emp compute statistics for table for all columns for all indexes; Table analyzed. kl@k02> select employee_id from te_emp where employee_id=107; (并没有走emp_id3, 而是emp_id1的INDEX RANGE SCAN) Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=3) 1 0 INDEX (RANGE SCAN) OF 'EMP_ID1' (UNIQUE) (Cost=1 Card=1 Bytes=3) kl@k02> drop index emp_id1; Index dropped. kl@k02> select employee_id from te_emp where employee_id=107; (drop原来的联合索引,用到了emp_id3,但是还是INDEX RANGE SCAN) Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=3) 1 0 INDEX (RANGE SCAN) OF 'EMP_ID3' (NON-UNIQUE) (Cost=1 Card=1 Bytes=3) (现在测试一下,如果组合index是unique index,会如何?) kl@k02> drop index emp_id3; Index dropped. kl@k02> create unique index emp_id1 on te_emp(employee_id,JOB_ID, department_id); Index created. kl@k02> analyze table te_emp compute statistics for table for all columns for all indexes; Table analyzed. kl@k02> select * from te_emp where employee_id=107 and JOB_ID='ENGINEER' and department_id=10; (此时走了unique scan,也就是说只有这种情况联合索引的作用才发挥出来) Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=62) 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TE_EMP' (Cost=1 Card=1 Bytes=62) 2 1 INDEX (UNIQUE SCAN) OF 'EMP_ID1' (UNIQUE) kl@k02> select * from te_emp where employee_id=107; (此时谓词内只有前导列,不会走unique scan) Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=62) 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TE_EMP' (Cost=2 Card=1 Bytes=62) 2 1 INDEX (RANGE SCAN) OF 'EMP_ID1' (NON-UNIQUE) (Cost=1 Card=1) kl@k02> select * from te_emp where employee_id=107 and JOB_ID=999 and department_id=10; (JOB_ID应该是Varchar型的,结果导致整个查询无法走Unique scan) Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=62) 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TE_EMP' (Cost=2 Card=1 Bytes=62) 2 1 INDEX (RANGE SCAN) OF 'EMP_ID1' (UNIQUE) (Cost=1 Card=1) kl@k02> select * from te_emp where employee_id='TEST' and JOB_ID='TEST' and department_id=10; (如果前导列类型出错了,索引扫描类型还是一样,UNIQUE SCAN) Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=62) 1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TE_EMP' (Cost=1 Card=1 Bytes=62) 2 1 INDEX (UNIQUE SCAN) OF 'EMP_ID1' (UNIQUE) 总结,针对组合索引,比较适宜的情况是组合列唯一,这种情况下对组合列建组合UNIQUE索引受益最大,一次索引扫描就可以了。但如果其中非前导列类型出错,索引UNIQUE扫描将变成RANGE SCAN; 有趣的是如果前导列类型不对,甚至为null,都不影响组合索引的UNIQUE SCAN. |
相关文章推荐
- oracle在组合索引上,只使用部分列进行查询(查询时必须包含前导列,否则会走全表扫描)
- 使用索引的误区之一:没有使用复合索引的前导列导致查询不使用索引——oracle
- Oracle性能优化,组合索引查询
- oracle查询表, 索引,唯一约束,字段
- 使用索引的误区之一:没有使用复合索引的前导列导致查询不使用索引
- Oracle 索引 bitmap 类型对 LIKE查询性能提升
- oracle使用了索引但是查询性能没有改善(oracle的索引陷阱) 【转】
- [慢查优化]建索引时注意字段选择性 & 范围查询注意组合索引的字段顺序
- 在oracle中查询所有用户表的表名、主键名称、索引、外键等
- 查询oracle表的信息(表,字段,约束,索引)
- 使用索引的误区之一:没有使用复合索引的前导列导致查询不使用索引
- oracle 查询语句索引建议
- Oracle查询语句中指定索引时优化器及指定索引不好使的处理方法
- Oracle中查询索引名称,批量修改索引名称语句
- Oracle Spacial(空间数据库)查询模型和空间索引
- Oracle 中查询所有用户、主键名称、外键、索引等
- 如何在oracle中查询所有用户表的表名、主键名称、索引、外键等
- oracle_为何在查询中索引未被使用
- oracle 12c 新特性之(相同字段上的多重索引、ddl 日志、限制PGA的大小、分页查询)
- Oracle组合索引与回表