分区索引分为本地(local index)索引和全局索引(global index)。对于local索引,每一个表分区对应一个索引分区,当表的分区发生变化时,索引的维护由Oracle自动进行。对于global索引,可以选择是否分区,而且索引的分区可以不与表分区相对应。当对分区进行维护操作时,通常会导致全局索引的INVALDED,必须在执行完操作后REBUILD。Oracle9i提供了UPDATE GLOBAL INDEXES语句,可以使在进行分区维护的同时重建全局索引其中本地索引又可以分为有前缀(prefix)的索引和无前缀(nonprefix)的索引。而全局索引目前只支持有前缀的索引。B树索引和位图索引都可以分区,但是HASH索引不可以被分区。位图索引必须是本地索引。下面就介绍本地索引以及全局索引各自的特点来说明区别;

一、本地索引特点:
1,本地索引一定是分区索引,分区键等同于表的分区键,分区数等同于表的分区说,一句话,本地索引的分区机制和表的分区机制一样。
2,如果本地索引的索引列以分区键开头,则称为前缀局部索引。
3,如果本地索引的列不是以分区键开头,或者不包含分区键列,则称为非前缀索引。
4,前缀和非前缀索引都可以支持索引分区消除,前提是查询的条件中包含索引分区键。
5,本地索引只支持分区内的唯一性,无法支持表上的唯一性,因此如果要用本地索引去给表做唯一性约束,则约束中必须要包括分区键列。
6,本地分区索引是对单个分区的,每个分区索引只指向一个表分区,全局索引则不然,一个分区索引能指向n个表分区,同时,一个表分区,也可能指向n个索引分区,对分区表中的某个分区做truncate或者move,shrink等,可能会影响到n个全局索引分区,正因为这点,本地分区索引具有更高的可用性。
7,位图索引只能为本地分区索引。
8,本地索引多应用于数据仓库环境中。
本地索引:创建了一个分区表后,如果需要在表上面创建索引,并且索引的分区机制和表的分区机制一样,那么这样的索引就叫做本地分区索引。本地索引是由ORACLE自动管理的,它分为有前缀的本地索引和无前缀的本地索引。什么叫有前缀的本地索引?有前缀的本地索引就是包含了分区键,并且将其作为引导列的索引。什么叫无前缀的本地索引?无前缀的本地索引就是没有将分区键的前导列作为索引的前导列的索引。下面举例说明:

create table test (id number,data varchar2(100))
 partition by RANGE (id)
 (
 partition p1 values less than (10000) tablespace p1,
 partition p2 values less than (20000) tablespace p2,
 partition p3 values less than (maxvalue) tablespace p3
 );create or replace procedure proc1
 as
 begin
  for i in 1..100000
  loop
   execute immediate
   'INSERT INTO warecountd values(:x,:y)' USING i,to_char(i+1000000);
  end loop;
 end;
 / SQL> exec proc1
PL/SQL procedure successfully completed.

create index i_id on test(id) local; 因为id是分区键,所以这样就创建了一个有前缀的本地索引。

SQL> select dbms_metadata.get_ddl('INDEX','I_ID','HR') index_name FROM DUAL;

看系统的对索引的metadata

SQL> set long 1000000
 SQL> select dbms_metadata.get_ddl('INDEX','I_ID','HR') index_name FROM DUAL;INDEX_NAME
 --------------------------------------------------------------------------------  CREATE INDEX "HR"."I_ID" ON "HR"."TEST" ("ID")
   PCTFREE 10 INITRANS 2 MAXTRANS 255
   STORAGE(
   BUFFER_POOL DEFAULT) LOCAL
  (PARTITION "P1"
   PCTFREE 10 INITRANS 2 MAXTRANS 255
   STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
   PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
   TABLESPACE "P1" ,
  PARTITION "P2"INDEX_NAME
 --------------------------------------------------------------------------------
   PCTFREE 10 INITRANS 2 MAXTRANS 255
   STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
   PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
   TABLESPACE "P2" ,
  PARTITION "P3"
   PCTFREE 10 INITRANS 2 MAXTRANS 255
   STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
   PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
   TABLESPACE "P3" )

当然你也可以用上面的语句创建index,也可以用下面的SQL语句创建:

SQL> drop index i_id;
Index dropped
SQL> CREATE INDEX "HR"."I_ID" ON "HR"."TEST" ("ID") LOCAL
  (PARTITION "P1" TABLESPACE "P1" , PARTITION "P2" TABLESPACE "P2" ,PARTITION "P3" TABLESPACE "P3" );Index created

create index i_data on test(data) local;因为data不是分区键,所以这样就创建了一个无前缀的本地索引。

看系统的对索引的metadata

SQL> select dbms_metadata.get_ddl('INDEX','I_DATA','HR') index_name FROM DUAL; 
INDEX_NAME
 --------------------------------------------------------------------------------  CREATE INDEX "HR"."I_DATA" ON "HR"."TEST" ("DATA")
   PCTFREE 10 INITRANS 2 MAXTRANS 255
   STORAGE(
   BUFFER_POOL DEFAULT) LOCAL
  (PARTITION "P1"
   PCTFREE 10 INITRANS 2 MAXTRANS 255
   STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
   PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
   TABLESPACE "P1" ,
  PARTITION "P2"INDEX_NAME
 --------------------------------------------------------------------------------
   PCTFREE 10 INITRANS 2 MAXTRANS 255
   STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
   PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
   TABLESPACE "P2" ,
  PARTITION "P3"
   PCTFREE 10 INITRANS 2 MAXTRANS 255
   STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
   PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
   TABLESPACE "P3" )

当然你也可以用上面的语句创建index,也可以用下面的SQL语句创建:

SQL> drop index i_data;
CREATE INDEX "HR"."I_DATA" ON "HR"."TEST" ("DATA") LOCAL (PARTITION "P1"  TABLESPACE "P1" ,PARTITION "P2"  TABLESPACE "P2" , PARTITION
"P3" TABLESPACE "P3" );

从user_part_indexes视图也可以证明刚才创建的索引,一个是有前缀的,一个是无前缀的

SQL> select index_name,table_name,partitioning_type,locality,ALIGNMENT from user_part_indexes;
INDEX_NAME                     TABLE_NAME                     PARTITI LOCALI ALIGNMENT
 ------------------------------ ------------------------------ ------- ------ ------------
 I_DATA                         TEST                           RANGE    LOCAL  NON_PREFIXED
I_ID                           TEST                           RANGE    LOCAL  PREFIXED

 

二、全局索引特点:
1,全局索引的分区键和分区数和表的分区键和分区数可能都不相同,表和全局索引的分区机制不一样。
2,全局索引可以分区,也可以是不分区索引,全局索引必须是前缀索引,即全局索引的索引列必须是以索引分区键作为其前几列。
3,全局分区索引的索引条目可能指向若干个分区,因此,对于全局分区索引,即使只截断一个分区中的数据,都需要rebulid若干个分区甚至是整个索引。
4,全局索引多应用于oltp系统中。
5,全局分区索引只按范围或者散列hash分区,hash分区是10g以后才支持。
6,oracle9i以后对分区表做move或者truncate的时可以用update global indexes语句来同步更新全局分区索引,用消耗一定资源来换取高度的可用性。
7,表用a列作分区,索引用b做局部分区索引,若where条件中用b来查询,那么oracle会扫描所有的表和索引的分区,成本会比分区更高,此时可以考虑用b做全局分区索引。

 

全局索引:与本地分区索引不同的是,全局分区索引的分区机制与表的分区机制不一样。全局分区索引全局分区索引只能是B树索引,到目前为止(10gR2),oracle只支持有前缀的全局索引。另外oracle不会自动的维护全局分区索引,当我们在对表的分区做修改之后,如果执行修改的语句不加上update global indexes的话,那么索引将不可用。以上面创建的分区表test为例,讲解全局分区索引:

SQL> DROP INDEX I_ID;
Index dropped.
 SQL> create index i_id_global on test(id) global
    partition by range(id)
    ( partition p1 values less than (10000) tablespace p1,
     partition p2 values less than (20000) tablespace p2,
     partition p3 values less than (MAXVALUE) tablespace p3
   );Index created

 

ORACLE默认不会自动维护全局分区索引,先注意看下status列,都是USABLE的

SQL> select INDEX_NAME,PARTITION_NAME,STATUS from user_ind_partitions where index_name='I_ID_GLOBAL';
INDEX_NAME                     PARTITION_NAME                 STATUS
 ------------------------------ ------------------------------ --------
 I_ID_GLOBAL                    P1                             USABLE
 I_ID_GLOBAL                    P2                             USABLE
 I_ID_GLOBAL                    P3                             USABLESQL> alter table test drop partition p2; ---注意看我做了DROP P2索引STATUS还是没有变
Table altered.
SQL> select INDEX_NAME,PARTITION_NAME,STATUS from user_ind_partitions where index_name='I_ID_GLOBAL';
INDEX_NAME                     PARTITION_NAME                 STATUS
 ------------------------------ ------------------------------ --------
 I_ID_GLOBAL                    P1                             USABLE
 I_ID_GLOBAL                    P2                             USABLE
 I_ID_GLOBAL                    P3                             USABLE 
SQL> create index i_id_global_data on test(data) global
  partition by range(id)
 ( partition p1 values less than (10000) tablespace p1,
  partition p2 values less than (20000) tablespace p2,
  partition p3 values less than (MAXVALUE) tablespace p3
  );ERROR at line 2:
 ORA-14038: GLOBAL partitioned index must be prefixed   即提示:GLOBAL  分区索引必须加上前缀 
 SQL> create bitmap index i_bmp_id_global on test(id) global
  partition by range(id)
 ( partition p1 values less than (10000) tablespace p1,
  partition p2 values less than (20000) tablespace p2,
  partition p3 values less than (MAXVALUE) tablespace p3
  );ERROR at line 1:
 ORA-25113: GLOBAL may not be used with a bitmap index   ---即提示:GLOBAL 可能无法与位图索引一起使用

三、Global分区索引不能够将其作为整体重建,必须对每个分区重建

SQL> alter index i_id_global rebuild online nologging;
 alter index i_id_global rebuild online nologging
             *
 ERROR at line 1:
 ORA-14086: a partitioned index may not be rebuilt as a whole  ---即不能将分区索引作为整体重建

这个时候可以通过查询dba_ind_partitions,或者user_ind_partitions,找到partition_name,然后对每个分区重建

SQL> select index_name,partition_name from user_ind_partitions where index_name='I_ID_GLOBAL';
INDEX_NAME                     PARTITION_NAME
 ------------------------------ ------------------------------
 I_ID_GLOBAL                    P1
 I_ID_GLOBAL                    P2
 I_ID_GLOBAL                    P3 SQL>  alter index i_id_global rebuild partition p1 online nologging;
Index altered.
SQL>  alter index i_id_global rebuild partition p2 online nologging;
Index altered.
SQL>  alter index i_id_global rebuild partition p3 online nologging;
Index altered.

四、关于分区索引的几个视图

dba_ind_partitions 描述了每个分区索引的分区情况,以及统计信息
dba_part_indexes   分区索引的概要统计信息,可以得知每个表上有哪些分区索引,分区索引的类型(local/global)