分區(qū)索引(或索引分區(qū))主要是針對分區(qū)表而言的。隨著數(shù)據(jù)量的不斷增長,普通的堆表需要轉(zhuǎn)換到分區(qū)表,其索引呢,則對應的轉(zhuǎn)換到分區(qū)索引。分區(qū)索引的好處是顯而易見的。就是簡單地把一個索引分成多個片斷,在獲取所需數(shù)據(jù)時,只需要訪問更小的索引片斷(塊)即可實現(xiàn)。同時把分區(qū)放在不同的表空間可以提高分區(qū)的可用性和可靠性。本文主要描述了分區(qū)索引的相關(guān)特性并給出演示示例。
--環(huán)境
SQL> select * from v$version where rownum2;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
SQL> create user leshami identified by xxx;
SQL> grant dba to leshami;
--創(chuàng)建演示需要用到的表空間
SQL> create tablespace tbs_tmp datafile '/u02/database/SYBO2/oradata/tbs_tmp.dbf' size 10m autoextend on;
SQL> alter user leshami default tablespace tbs_tmp;
SQL> create tablespace tbs1 datafile '/u02/database/SYBO2/oradata/tbs1.dbf' size 10m autoextend on;
SQL> create tablespace tbs2 datafile '/u02/database/SYBO2/oradata/tbs2.dbf' size 10m autoextend on;
SQL> create tablespace tbs3 datafile '/u02/database/SYBO2/oradata/tbs3.dbf' size 10m autoextend on;
SQL> create tablespace idx1 datafile '/u02/database/SYBO2/oradata/idx1.dbf' size 10m autoextend on;
SQL> create tablespace idx2 datafile '/u02/database/SYBO2/oradata/idx2.dbf' size 10m autoextend on;
SQL> create tablespace idx3 datafile '/u02/database/SYBO2/oradata/idx3.dbf' size 10m autoextend on;
SQL> conn leshami/xxx
-- 創(chuàng)建一個lookup表
CREATE TABLE lookup (
id NUMBER(10),
description VARCHAR2(50)
);
--添加主鍵約束
ALTER TABLE lookup ADD (
CONSTRAINT lookup_pk PRIMARY KEY (id)
);
--插入數(shù)據(jù)
INSERT INTO lookup (id, description) VALUES (1, 'ONE');
INSERT INTO lookup (id, description) VALUES (2, 'TWO');
INSERT INTO lookup (id, description) VALUES (3, 'THREE');
COMMIT;
CREATE TABLE big_table (
id NUMBER(10),
created_date DATE,
lookup_id NUMBER(10),
data VARCHAR2(50)
)
PARTITION BY RANGE (created_date)
(PARTITION big_table_2012 VALUES LESS THAN (TO_DATE('01/01/2013', 'DD/MM/YYYY')) tablespace tbs1,
PARTITION big_table_2013 VALUES LESS THAN (TO_DATE('01/01/2014', 'DD/MM/YYYY')) tablespace tbs2,
PARTITION big_table_2014 VALUES LESS THAN (MAXVALUE)tablespace tbs3 ) ;
--填充數(shù)據(jù)到分區(qū)表
DECLARE
l_lookup_id lookup.id%TYPE;
l_create_date DATE;
BEGIN
FOR i IN 1 .. 10000 LOOP
IF MOD(i, 3) = 0 THEN
l_create_date := ADD_MONTHS(SYSDATE, -24);
l_lookup_id := 2;
ELSIF MOD(i, 2) = 0 THEN
l_create_date := ADD_MONTHS(SYSDATE, -12);
l_lookup_id := 1;
ELSE
l_create_date := SYSDATE;
l_lookup_id := 3;
END IF;
INSERT INTO big_table (id, created_date, lookup_id, data)
VALUES (i, l_create_date, l_lookup_id, 'This is some data for ' || i);
END LOOP;
COMMIT;
END;
/
--未指定索引分區(qū)及存儲表空間情形下創(chuàng)建索引
SQL> CREATE INDEX bita_created_date_i ON big_table(created_date) LOCAL;
Index created.
SQL> select index_name, partitioning_type, partition_count from user_part_indexes;
INDEX_NAME PARTITI PARTITION_COUNT
------------------------------ ------- ---------------
BITA_CREATED_DATE_I RANGE 3
--Author : Leshami
--從下面的查詢可知,索引直接存放到分表表對應的表空間
SQL> select partition_name, high_value, tablespace_name from user_ind_partitions;
PARTITION_NAME HIGH_VALUE TABLESPACE_NAME
------------------------------ ---------------------------------------- ------------------------------
BIG_TABLE_2014 MAXVALUE TBS3
BIG_TABLE_2013 TO_DATE(' 2014-01-01 00:00:00', 'SYYYY-M TBS2
M-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
BIG_TABLE_2012 TO_DATE(' 2013-01-01 00:00:00', 'SYYYY-M TBS1
M-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
--刪除索引
SQL> drop index bita_created_date_i;
--指定索引分區(qū)名表空間名創(chuàng)建索引
SQL> CREATE INDEX bita_created_date_i
2 ON big_table (created_date)
3 LOCAL (
4 PARTITION idx_2012 TABLESPACE idx1,
5 PARTITION idx_2013 TABLESPACE idx2,
6 PARTITION idx_2014 TABLESPACE idx3)
7 PARALLEL 3;
Index created.
SQL> select partition_name, high_value, tablespace_name from user_ind_partitions;
PARTITION_NAME HIGH_VALUE TABLESPACE_NAME
------------------------------ ---------------------------------------- ------------------------------
IDX_2014 MAXVALUE IDX3
IDX_2013 TO_DATE(' 2014-01-01 00:00:00', 'SYYYY-M IDX2
M-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
IDX_2012 TO_DATE(' 2013-01-01 00:00:00', 'SYYYY-M IDX1
M-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA
SQL> select * from big_table where rownum2;
ID CREATED_ LOOKUP_ID DATA
---------- -------- ---------- --------------------------------------------------
1413 20120625 2 This is some data for 1413
--查看local index是否被使用,從下面的執(zhí)行計劃中可知,索引被使用,支持分區(qū)消除
SQL> set autot trace exp;
SQL> select * from big_table where created_date=to_date('20120625','yyyymmdd');
Execution Plan
----------------------------------------------------------
Plan hash value: 2556877094
--------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
--------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 41 | 2 (0)| 00:00:01 | | |
| 1 | PARTITION RANGE SINGLE | | 1 | 41 | 2 (0)| 00:00:01 | 1 | 1 |
| 2 | TABLE ACCESS BY LOCAL INDEX ROWID| BIG_TABLE | 1 | 41 | 2 (0)| 00:00:01 | 1 | 1 |
|* 3 | INDEX RANGE SCAN | BITA_CREATED_DATE_I | 1 | | 1 (0)| 00:00:01 | 1 | 1 |
--------------------------------------------------------------------------------------------------------------------------
--為表添加主鍵
SQL> ALTER TABLE big_table ADD (
2 CONSTRAINT big_table_pk PRIMARY KEY (id)
3 );
Table altered.
SQL> select index_name,index_type,tablespace_name,global_stats,partitioned
2 from user_indexes where index_name='BIG_TABLE_PK';
INDEX_NAME INDEX_TYPE TABLESPACE_NAME GLO PAR
------------------------------ --------------------------- ------------------------------ --- ---
BIG_TABLE_PK NORMAL TBS_TMP YES NO
SQL> set autot trace exp;
SQL> select * from big_table where id=1412;
Execution Plan
----------------------------------------------------------
Plan hash value: 2662411593
-------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 62 | 2 (0)| 00:00:01 | | |
| 1 | TABLE ACCESS BY GLOBAL INDEX ROWID| BIG_TABLE | 1 | 62 | 2 (0)| 00:00:01 | ROWID | ROWID |
|* 2 | INDEX UNIQUE SCAN | BIG_TABLE_PK | 1 | | 1 (0)| 00:00:01 | | |
-------------------------------------------------------------------------------------------------------------------
--如上,在其執(zhí)行計劃中,Pstart與Pstop都為ROWID
--出現(xiàn)了GLOBAL INDEX ROWID,我們添加主鍵時并未指定Global,但其執(zhí)行計劃表明執(zhí)行了全局索引訪問
--這個地方有待證實,對于分區(qū)表,非分區(qū)鍵上的主鍵或唯一索引是否一定是全局索引
SQL> drop index bita_created_date_i;
--下面創(chuàng)建全局索引,創(chuàng)建時需要指定分區(qū)鍵的范圍和值
SQL> CREATE INDEX bita_created_date_i
ON big_table (created_date)
GLOBAL PARTITION BY RANGE (created_date)
(
PARTITION
idx_1 VALUES LESS THAN (TO_DATE ('01/01/2013', 'DD/MM/YYYY'))
TABLESPACE idx1,
PARTITION
idx_2 VALUES LESS THAN (TO_DATE ('01/01/2014', 'DD/MM/YYYY'))
TABLESPACE idx2,
PARTITION idx_3 VALUES LESS THAN (maxvalue) TABLESPACE idx3);
SQL> select index_name, partitioning_type, partition_count,locality from user_part_indexes;
INDEX_NAME PARTITI PARTITION_COUNT LOCALI
------------------------------ ------- --------------- ------
BITA_CREATED_DATE_I_G RANGE 3 GLOBAL
SQL> select partition_name, high_value, tablespace_name from user_ind_partitions;
PARTITION_NAME HIGH_VALUE TABLESPACE_NAME
------------------------------ --------------------- ------------------------------
IDX_1 TO_DATE(' 2013-01-01 IDX1
IDX_2 TO_DATE(' 2014-01-01 IDX2
IDX_3 MAXVALUE IDX3
--下面是其執(zhí)行計劃,可以看出支持分區(qū)消除
SQL> set autot trace exp;
SQL> select * from big_table where created_date=to_date('20130625','yyyymmdd');
Execution Plan
----------------------------------------------------------
Plan hash value: 1378264218
---------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
---------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 41 | 2 (0)| 00:00:01 | | |
| 1 | PARTITION RANGE SINGLE | | 1 | 41 | 2 (0)| 00:00:01 | 2 | 2 |
| 2 | TABLE ACCESS BY GLOBAL INDEX ROWID| BIG_TABLE | 1 | 41 | 2 (0)| 00:00:01 | 2 | 2 |
|* 3 | INDEX RANGE SCAN | BITA_CREATED_DATE_I | 1 | | 1 (0)| 00:00:01 | 2 | 2 |
---------------------------------------------------------------------------------------------------------------------------
--以下為范圍查詢,Pstart為1,Pstop為2,同樣支持分區(qū)消除
SQL> select * from big_table
2 where created_date>=to_date('20120625','yyyymmdd') and created_date=to_date('20130625','yyyymmdd');
Execution Plan
----------------------------------------------------------
Plan hash value: 213633793
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3334 | 133K| 14 (0)| 00:00:01 | | |
| 1 | PARTITION RANGE ITERATOR| | 3334 | 133K| 14 (0)| 00:00:01 | 1 | 2 |
|* 2 | TABLE ACCESS FULL | BIG_TABLE | 3334 | 133K| 14 (0)| 00:00:01 | 1 | 2 |
------------------------------------------------------------------------------------------------------