您的位置:首页 > 其它

复合索引的前导列如何选择?

2013-09-18 09:51 363 查看
     在表上建复合索引是常见的事情,那索引中键值的顺序是什么呢?通过下面的实验可以得出三个结论:

--制造实验数据,并收集统计信息

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: