复合索引的前导列如何选择?
在表上建复合索引是常见的事情,那索引中键值的顺序是什么呢?通过下面的实验可以得出三个结论:
--制造实验数据,并收集统计信息
SQL> create table test as select * from dba_objects;
SQL> create index ind_id_owner on test(object_id,owner);
SQL> create index ind_owner_id on test(owner,object_id);
SQL> exec dbms_stats.gather_table_stats(user,'test',cascade=>true);
SQL> select count(distinct owner) owner_count, count(distinct object_id) id_count, count(*) from test;
OWNER_COUNT ID_COUNT COUNT(*)
----------- ---------- ----------
25 50583 50584
SQL> set autotrace traceonly
1. 如果是等值查询,那字段无先后之分,结合着索引的存储结构,索引存储的是键值和rowid,复合索引就是存储两个键值,如果是等值查询,可以看作是一个值,跟单个字段索引查询一样。
SQL> select /*+index(test,ind_id_owner)*/* from test where owner ='TEST' and object_id =52623;
执行计划
----------------------------------------------------------
Plan hash value: 1096520809
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 93 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 93 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IND_ID_OWNER | 1 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID"=52623 AND "OWNER"='TEST')
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
4 consistent gets
0 physical reads
0 redo size
1199 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> select /*+index(test,ind_owner_id)*/* from test where owner ='TEST' and object_id =52623;
执行计划
----------------------------------------------------------
Plan hash value: 724495818
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 93 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 93 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IND_OWNER_ID | 1 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='TEST' AND "OBJECT_ID"=52623)
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
4 consistent gets
0 physical reads
0 redo size
1199 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
2. 如果是一个是等值,一个是范围查询,等值的字段作为前导列好一些。同样结合索引的存储特性,如果是object_id作为前导列,那oracle 会扫描30000,test到50584,***的数据,丢弃owner !=‘TEST’的列。
如果是owner作为前导列,那oracle 会扫描test,30000到test,50584的数据,没有丢弃。
SQL> select /*+index(test,ind_id_owner)*/* from test where owner ='TEST' and object_id >=30000;
已选择148行。
执行计划
----------------------------------------------------------
Plan hash value: 1096520809
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1076 | 97K| 90 (2)| 00:00:02 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1076 | 97K| 90 (2)| 00:00:02 |
|* 2 | INDEX RANGE SCAN | IND_ID_OWNER | 1076 | | 73 (2)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID">=30000 AND "OWNER"='TEST' AND "OBJECT_ID" IS NOT NULL)
filter("OWNER"='TEST')
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
114 consistent gets
0 physical reads
0 redo size
17139 bytes sent via SQL*Net to client
484 bytes received via SQL*Net from client
11 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
148 rows processed
SQL> select /*+index(test,ind_owner_id)*/* from test where owner ='TEST' and object_id >=30000;
已选择148行。
执行计划
----------------------------------------------------------
Plan hash value: 724495818
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1076 | 97K| 36 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1076 | 97K| 36 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IND_OWNER_ID | 1076 | | 5 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='TEST' AND "OBJECT_ID">=30000 AND "OBJECT_ID" IS NOT NULL)
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
50 consistent gets
0 physical reads
0 redo size
17139 bytes sent via SQL*Net to client
484 bytes received via SQL*Net from client
11 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
148 rows processed
3. 如果两个条件都是范围查询,则前导列为,单个字段过滤后的数据量接近两个字段过滤后的数据量。以下面的列子来说,最终结果是830条数据,用 owner >='TEST'为1076条,用object_id >= 30000是21029条,这样会减少filter的操作,所以选择owner作为前导列。
SQL> select /*+index(test,ind_id_owner)*/*from test where owner >='TEST' and object_id >= 30000;
已选择830行。
执行计划
----------------------------------------------------------
Plan hash value: 1096520809
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5377 | 488K| 156 (1)| 00:00:02 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 5377 | 488K| 156 (1)| 00:00:02 |
|* 2 | INDEX RANGE SCAN | IND_ID_OWNER | 5377 | | 73 (2)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID">=30000 AND "OWNER">='TEST' AND "OBJECT_ID" IS NOT NULL)
filter("OWNER">='TEST')
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
228 consistent gets
0 physical reads
0 redo size
86578 bytes sent via SQL*Net to client
990 bytes received via SQL*Net from client
57 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
830 rows processed
SQL> select /*+index(test,ind_owner_id)*/*from test where owner >='TEST' and object_id >= 30000;
已选择830行。
执行计划
----------------------------------------------------------
Plan hash value: 724495818
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5377 | 488K| 188 (1)| 00:00:03 |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 5377 | 488K| 188 (1)| 00:00:03 |
|* 2 | INDEX RANGE SCAN | IND_OWNER_ID | 5377 | | 36 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER">='TEST' AND "OBJECT_ID">=30000 AND "OWNER" IS NOT NULL)
filter("OBJECT_ID">=30000)
统计信息
----------------------------------------------------------
1 recursive calls
0 db block gets
164 consistent gets
0 physical reads
0 redo size
86578 bytes sent via SQL*Net to client
990 bytes received via SQL*Net from client
57 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
830 rows processed
SQL> set autotrace off
SQL> select count(*) from test where owner >='TEST';
COUNT(*)
----------
1076
SQL> select count(*) from test where object_id >= 30000;
COUNT(*)
----------
21029
相关 [复合 索引 选择] 推荐:
mysql选择索引
- - CSDN博客数据库推荐文章复合索引性能问题初探
- - CSDN博客推荐文章复合地板、竹地板、实木地板 应该如何选择?
- - 知乎每日精选从性能的角度谈SQL Server聚集索引键的选择
- - CSDN博客数据库推荐文章转载 选择
- bravusliu - caowumao的博客CSS4 选择器
- iVane - 幸福收藏夹JQuery 选择器
- - CSDN博客Web前端推荐文章点击我
. 像上面这样把JavaSript代码和HTML代码混杂在一起的做法同样也非常不妥,因为它并没有将网页内容和行为分离,所以才有JQuery选择器的学习.点击我
. //给class为demo的元素添加行为.