组合索引和单列索引效率对比

SQL> create table test(object_id NUMBER,object_name varchar2(10));



Table created.



SQL> begin

  2  for i in 1 .. 1000000

  3  loop

  4  insert into test values (1,'TEST');

  5  end loop; 

  6  end;

  7  /



PL/SQL procedure successfully completed.





SQL> begin

  2  for i in  1 .. 300

  3  loop

  4  insert into test values (2,'TEST2');

  5  end loop;

  6  end;

  7  /



PL/SQL procedure successfully completed.



SQL> begin

  2  for i in  1 .. 49700

  3  loop

  4  insert into test values (2,i||'TEST2');

  5  end loop;

  6  end;

  7  /



SQL> select count(*), object_id from test group by object_id;



  COUNT(*)  OBJECT_ID

---------- ----------

   1000000	    1

     50000	    2







SQL>  select count(*) from test where object_name='TEST2' and object_id=2;



  COUNT(*)

----------

       300



SQL> select count(*) from test where object_name<>'TEST2' and object_id=2;



  COUNT(*)

----------

     49700



第一种情况:

TABLE ACCESS BY INDEX ROWID 前面有 *,并且INDEX RANGE SCAN返回5w条,5W个rowid,过滤object_name之后只剩下 300条 那么就建组合索引





在object_id列创建索引

SQL> create index test_idx1 on test(OBJECT_ID);



Index created.



BEGIN

  DBMS_STATS.GATHER_TABLE_STATS(ownname          => 'TEST',

                                tabname          => 'TEST',

                                estimate_percent => 100,

                                method_opt       => 'for all columns size skewonly',

                                no_invalidate    => FALSE,

                                degree           => 8,

                                cascade          => TRUE);

END;



SQL> select * from test where object_id=2 and object_name='TEST2';



300 rows selected.





Execution Plan

----------------------------------------------------------

Plan hash value: 2624864549



-----------------------------------------------------------------------------------------

| Id  | Operation		    | Name	| Rows	| Bytes | Cost (%CPU)| Time	|

-----------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT	    |		|     1 |     8 |   198   (1)| 00:00:03 |

|*  1 |  TABLE ACCESS BY INDEX ROWID| TEST	|     1 |     8 |   198   (1)| 00:00:03 |

|*  2 |   INDEX RANGE SCAN	    | TEST_IDX1 | 50000 |	|   100   (0)| 00:00:02 |

-----------------------------------------------------------------------------------------



Predicate Information (identified by operation id):

---------------------------------------------------



   1 - filter("OBJECT_NAME"='TEST2')

   2 - access("OBJECT_ID"=2)





Statistics

----------------------------------------------------------

	  1  recursive calls

	  0  db block gets

	270  consistent gets

	  0  physical reads

	  0  redo size

       4441  bytes sent via SQL*Net to client

	628  bytes received via SQL*Net from client

	 21  SQL*Net roundtrips to/from client

	  0  sorts (memory)

	  0  sorts (disk)

	300  rows processed

SQL> select count(*) from test;



  COUNT(*)

----------

   1050000



SQL>  select count(*) from test where object_id=2;



  COUNT(*)

----------

     50000



SQL> select count(*) from test where object_id=2 and object_name='TEST2';



  COUNT(*)

----------

       300



TEST表总共1050000行,其中INDEX RANGE SCAN后返回50000行,过滤object_name之后只剩下 300条 那么就建组合索引



建立组合索引;

SQL> select * from test where object_id=2 and object_name='TEST2';



300 rows selected.





Execution Plan

----------------------------------------------------------

Plan hash value: 415678261



------------------------------------------------------------------------------

| Id  | Operation	 | Name      | Rows  | Bytes | Cost (%CPU)| Time     |

------------------------------------------------------------------------------

|   0 | SELECT STATEMENT |	     |	   1 |	   8 |	   3   (0)| 00:00:01 |

|*  1 |  INDEX RANGE SCAN| TEST_IDX2 |	   1 |	   8 |	   3   (0)| 00:00:01 |

------------------------------------------------------------------------------



Predicate Information (identified by operation id):

---------------------------------------------------



   1 - access("OBJECT_ID"=2 AND "OBJECT_NAME"='TEST2')





Statistics

----------------------------------------------------------

	  1  recursive calls

	  0  db block gets

	 24  consistent gets

	  0  physical reads

	  0  redo size

       4441  bytes sent via SQL*Net to client

	628  bytes received via SQL*Net from client

	 21  SQL*Net roundtrips to/from client

	  0  sorts (memory)

	  0  sorts (disk)

	300  rows processed



如果组合起来的话不需要过滤,不需要回表,直接返回300行







第2种情况:

INDEX RANGE SCAN 返回5W 回表过滤后返回数据还很多,不需要创建组合索引的情况。

 begin

    for i in 1 .. 1000000

    loop

    insert into test values (1,'TEST');

    end loop; 

    end;





 begin

    for i in  1 .. 49000

    loop

    insert into test values (2,'TEST2');

   end loop;

    end;

   







 begin

    for i in  1 .. 100

    loop

    insert into test values (2,'TEST3');

   end loop;

    end;

   



SQL>  select count(*),object_id,object_name from test

   where object_id=2

    group by object_id,object_name  2    3  ;



  COUNT(*)  OBJECT_ID OBJECT_NAM

---------- ---------- ----------

     49000	    2 TEST2

       100	    2 TEST3

SQL> select * from test where object_id=2 and object_name='TEST2';



49000 rows selected.





Execution Plan

----------------------------------------------------------

Plan hash value: 2624864549



-----------------------------------------------------------------------------------------

| Id  | Operation		    | Name	| Rows	| Bytes | Cost (%CPU)| Time	|

-----------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT	    |		|  2293 | 18344 |   188   (1)| 00:00:03 |

|*  1 |  TABLE ACCESS BY INDEX ROWID| TEST	|  2293 | 18344 |   188   (1)| 00:00:03 |

|*  2 |   INDEX RANGE SCAN	    | TEST_IDX1 | 49100 |	|    98   (0)| 00:00:02 |

-----------------------------------------------------------------------------------------



Predicate Information (identified by operation id):

---------------------------------------------------



   1 - filter("OBJECT_NAME"='TEST2')

   2 - access("OBJECT_ID"=2)





Statistics

----------------------------------------------------------

	  1  recursive calls

	  0  db block gets

       6715  consistent gets

	 98  physical reads

	  0  redo size

     660310  bytes sent via SQL*Net to client

      36345  bytes received via SQL*Net from client

       3268  SQL*Net roundtrips to/from client

	  0  sorts (memory)

	  0  sorts (disk)

      49000  rows processed



INDEX RANGE SCAN 返回49100行,过滤"OBJECT_NAME"='TEST2'后返回49000行



创建组合索引:

SQL> create index test_Idx2 on test(object_id,object_name);



Index created.



SQL> select * from test where object_id=2 and object_name='TEST2';



49000 rows selected.





Execution Plan

----------------------------------------------------------

Plan hash value: 415678261



------------------------------------------------------------------------------

| Id  | Operation	 | Name      | Rows  | Bytes | Cost (%CPU)| Time     |

------------------------------------------------------------------------------

|   0 | SELECT STATEMENT |	     |	2293 | 18344 |	   9   (0)| 00:00:01 |

|*  1 |  INDEX RANGE SCAN| TEST_IDX2 |	2293 | 18344 |	   9   (0)| 00:00:01 |

------------------------------------------------------------------------------



Predicate Information (identified by operation id):

---------------------------------------------------



   1 - access("OBJECT_ID"=2 AND "OBJECT_NAME"='TEST2')





Statistics

----------------------------------------------------------

	  1  recursive calls

	  0  db block gets

       3398  consistent gets

	139  physical reads

	  0  redo size

     660310  bytes sent via SQL*Net to client

      36345  bytes received via SQL*Net from client

       3268  SQL*Net roundtrips to/from client

	  0  sorts (memory)

	  0  sorts (disk)

      49000  rows processed





可以看到就算INDEX RANGE SCAN返回49100行,通过过滤"OBJECT_NAME"='TEST2',虽然只过滤了100行,但还是走组合索引效率高。

-------------------------------------------------------------------------------------------------------------------



那什么情况会出现组合索引比单列索引效率低呢?

select  XLBHZ XLBHZ,ZDBHZ ZDBHZ, jyrqz,

               decode(JCZBZ, '0', sum(JYBSZ), 0) TOKEN_JKLZZ,

               decode(JCZBZ, '1', sum(JYBSZ), 0) TOKEN_CKLZZ,

               0 CASH_JKLZZ,

               0 CASH_CKLZZ,

               0 TFT_JKLZZ,

               0 TFT_CKLZZ

          from brt_hzjcztok

          where 1=1 AND XLBHZ IN ('0001','0002') AND  JYRQZ>='20130727' AND JYRQZ<='20130728'

         group by jyrqz, JCZBZ,XLBHZ,ZDBHZ





Execution Plan

----------------------------------------------------------

Plan hash value: 1433290359



---------------------------------------------------------------------------------------------------

| Id  | Operation                    | Name               | Rows  | Bytes | Cost (%CPU)| Time     |

---------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT             |                    |  3757 | 93925 |  2604   (1)| 00:00:32 |

|   1 |  SORT GROUP BY NOSORT        |                    |  3757 | 93925 |  2604   (1)| 00:00:32 |

|   2 |   TABLE ACCESS BY INDEX ROWID| BRT_HZJCZTOK       |  3757 | 93925 |  2604   (1)| 00:00:32 |

|*  3 |    INDEX RANGE SCAN          | IDX_HZJCZTOK_UNION |  3757 |       |    20   (0)| 00:00:01 |

---------------------------------------------------------------------------------------------------



Predicate Information (identified by operation id):

---------------------------------------------------



   3 - access("JYRQZ">='20130727' AND "JYRQZ"<='20130728')

       filter("XLBHZ"='0001' OR "XLBHZ"='0002')





原先索引:

IDX_HZJCZTOK_UNION(JYRQZ, JCZBZ, XLBHZ, ZDBHZ)





Statistics

----------------------------------------------------------

          0  recursive calls

          0  db block gets

       2670  consistent gets

          0  physical reads

          0  redo size

      10149  bytes sent via SQL*Net to client

        646  bytes received via SQL*Net from client

         16  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

        224  rows processed

        



Execution Plan

----------------------------------------------------------

Plan hash value: 2641846428



-----------------------------------------------------------------------------------

| Id  | Operation          | Name         | Rows  | Bytes | Cost (%CPU)| Time     |

-----------------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |              |  3757 | 93925 |   203   (5)| 00:00:03 |

|   1 |  HASH GROUP BY     |              |  3757 | 93925 |   203   (5)| 00:00:03 |

|*  2 |   TABLE ACCESS FULL| BRT_HZJCZTOK |  3757 | 93925 |   201   (4)| 00:00:03 |

-----------------------------------------------------------------------------------



Predicate Information (identified by operation id):

---------------------------------------------------



   2 - filter("JYRQZ">='20130727' AND "JYRQZ"<='20130728' AND

              ("XLBHZ"='0001' OR "XLBHZ"='0002'))





Statistics

----------------------------------------------------------

          1  recursive calls

          0  db block gets

        947  consistent gets

          0  physical reads

          0  redo size

      10333  bytes sent via SQL*Net to client

        646  bytes received via SQL*Net from client

         16  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

        224  rows processed

        

同个sql,一个强制索引,一个没有强制走全表,你觉得这2个执行计划哪个好?









--select count(*) from brt_hzjcztok where JYRQZ>='20130727' AND JYRQZ<='20130728'

3885



全部数据呢



---select count(*) from brt_hzjcztok 

128023





SQL> select XLBHZ,count(*) from brt_hzjcztok group by XLBHZ order by count(*) desc;



XLBH   COUNT(*)

---- ----------

0002      64131

0001      63849

0100         43





create index brt_hzjcztok_idx1 on brt_hzjcztok(JYRQZ,XLBHZ);



或者直接创建

create index brt_hzjcztok_idx1 on brt_hzjcztok(JYRQZ);



原来网友自己创建的索引:



IDX_HZJCZTOK_UNION(JYRQZ, JCZBZ, XLBHZ, ZDBHZ)



------------------------------------------------------------------------------------------



-------------------------------------------------------------------------------------------

create index brt_hzjcztok_idx1 on brt_hzjcztok(JYRQZ,XLBHZ);        

        

Execution Plan

----------------------------------------------------------

Plan hash value: 497111649



--------------------------------------------------------------------------------------------------

| Id  | Operation                    | Name              | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT             |                   |  3757 | 93925 |    85   (3)| 00:00:02 |

|   1 |  HASH GROUP BY               |                   |  3757 | 93925 |    85   (3)| 00:00:02 |

|   2 |   TABLE ACCESS BY INDEX ROWID| BRT_HZJCZTOK      |  3757 | 93925 |    83   (0)| 00:00:02 |

|*  3 |    INDEX RANGE SCAN          | BRT_HZJCZTOK_IDX1 |  3757 |       |    16   (0)| 00:00:01 |

--------------------------------------------------------------------------------------------------



Predicate Information (identified by operation id):

---------------------------------------------------



   3 - access("JYRQZ">='20130727' AND "JYRQZ"<='20130728')

       filter("XLBHZ"='0001' OR "XLBHZ"='0002')





Statistics

----------------------------------------------------------

          0  recursive calls

          0  db block gets

         79  consistent gets

          0  physical reads

          0  redo size

      10363  bytes sent via SQL*Net to client

        646  bytes received via SQL*Net from client

         16  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

        224  rows processed



SQL> /



DROP INDEX brt_hzjcztok_idx1

create index brt_hzjcztok_idx1 on brt_hzjcztok(JYRQZ);



224 rows selected.





Execution Plan

----------------------------------------------------------

Plan hash value: 497111649



--------------------------------------------------------------------------------------------------

| Id  | Operation                    | Name              | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT             |                   |  3757 | 93925 |    48   (5)| 00:00:01 |

|   1 |  HASH GROUP BY               |                   |  3757 | 93925 |    48   (5)| 00:00:01 |

|*  2 |   TABLE ACCESS BY INDEX ROWID| BRT_HZJCZTOK      |  3757 | 93925 |    46   (0)| 00:00:01 |

|*  3 |    INDEX RANGE SCAN          | BRT_HZJCZTOK_IDX1 |  3757 |       |    12   (0)| 00:00:01 |

--------------------------------------------------------------------------------------------------



Predicate Information (identified by operation id):

---------------------------------------------------



   2 - filter("XLBHZ"='0001' OR "XLBHZ"='0002')

   3 - access("JYRQZ">='20130727' AND "JYRQZ"<='20130728')





Statistics

----------------------------------------------------------

          1  recursive calls

          0  db block gets

         44  consistent gets

          0  physical reads

          0  redo size

      10333  bytes sent via SQL*Net to client

        646  bytes received via SQL*Net from client

         16  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

        224  rows processed





这里是--select count(*) from brt_hzjcztok where JYRQZ>='20130727' AND JYRQZ<='20130728'

3885 走INDEX RANGE SCAN后返回3885条记录后,在过滤43条记录。








 

你可能感兴趣的:(索引)