创建分区表
create table part_tab (id int,col2 int,col3 int) tablespace users
partition by range(id)
(
partition p1 values less than (10000),
partition p2 values less than (20000),
partition p3 values less than (30000),
partition p4 values less than (40000),
partition p5 values less than (50000),
partition p6 values less than (60000),
partition p7 values less than (70000),
partition p8 values less than (80000),
partition p9 values less than (90000),
partition p10 values less than (100000),
partition p11 values less than (maxvalue)
);
插入数据
insert into part_tab select rownum,rownum+1,rownum+2 from dual connect by rownum<=110000;
commit;
在col2上建立局部索引
create index idx_par_tab_col2 on part_tab(col2) local tablespace users;
在col3 上建立全局索引。 并查看表段的情况
create index idx_par_tab_col3 on part_tab(col3) tablespace users;
select segment_name,partition_name,segment_type from dba_segments where segment_name='PART_TAB';
SEGMENT_NA PARTIT SEGMENT_TYPE
---------- ------ --------------------
PART_TAB P9 TABLE PARTITION
PART_TAB P8 TABLE PARTITION
PART_TAB P7 TABLE PARTITION
PART_TAB P6 TABLE PARTITION
PART_TAB P5 TABLE PARTITION
PART_TAB P4 TABLE PARTITION
PART_TAB P3 TABLE PARTITION
PART_TAB P2 TABLE PARTITION
PART_TAB P11 TABLE PARTITION
PART_TAB P10 TABLE PARTITION
PART_TAB P1 TABLE PARTITION
11 rows selected.
查看局部索引段idx_par_tab_col2的情况.可以看到,每个分区对应一个索引段,有几个分区,就有几个索引段。
select segment_name,partition_name,segment_type from dba_segments where segment_name='IDX_PAR_TAB_COL2';
SEGMENT_NAME PARTIT SEGMENT_TYPE
------------------------------ ------ --------------------
IDX_PAR_TAB_COL2 P9 INDEX PARTITION
IDX_PAR_TAB_COL2 P8 INDEX PARTITION
IDX_PAR_TAB_COL2 P7 INDEX PARTITION
IDX_PAR_TAB_COL2 P6 INDEX PARTITION
IDX_PAR_TAB_COL2 P5 INDEX PARTITION
IDX_PAR_TAB_COL2 P4 INDEX PARTITION
IDX_PAR_TAB_COL2 P3 INDEX PARTITION
IDX_PAR_TAB_COL2 P2 INDEX PARTITION
IDX_PAR_TAB_COL2 P11 INDEX PARTITION
IDX_PAR_TAB_COL2 P10 INDEX PARTITION
IDX_PAR_TAB_COL2 P1 INDEX PARTITION
11 rows selected.
查看全局索引段idx_par_tab_col3的情况。可以看到,整个分区表,只有1个索引段
select segment_name,partition_name,segment_type from dba_segments where segment_name='IDX_PAR_TAB_COL3';
SYS@test>select segment_name,partition_name,segment_type from dba_segments where segment_name='IDX_PAR_TAB_COL3';
SEGMENT_NAME PARTIT SEGMENT_TYPE
------------------------------ ------ --------------------
IDX_PAR_TAB_COL3 INDEX
SYS@test>
查询索引的状态。 因为索引idx_par_tab_col2是分区索引(Local),要查询dba_ind_partitions
select index_name,partition_name,status from dba_ind_partitions where index_name='IDX_PAR_TAB_COL2';
select index_name,partition_name,status from dba_ind_partitions where index_name='IDX_PAR_TAB_COL3';
SYS@test>select index_name,partition_name,status from dba_ind_partitions where index_name='IDX_PAR_TAB_COL2';
INDEX_NAME PARTIT STATUS
------------------------------ ------ --------
IDX_PAR_TAB_COL2 P1 USABLE
IDX_PAR_TAB_COL2 P10 USABLE
IDX_PAR_TAB_COL2 P11 USABLE
IDX_PAR_TAB_COL2 P2 USABLE
IDX_PAR_TAB_COL2 P3 USABLE
IDX_PAR_TAB_COL2 P4 USABLE
IDX_PAR_TAB_COL2 P5 USABLE
IDX_PAR_TAB_COL2 P6 USABLE
IDX_PAR_TAB_COL2 P7 USABLE
IDX_PAR_TAB_COL2 P8 USABLE
IDX_PAR_TAB_COL2 P9 USABLE
11 rows selected.
SYS@test>select index_name,partition_name,status from dba_ind_partitions where index_name='IDX_PAR_TAB_COL3';
no rows selected
SYS@test>
select index_name,index_type, status from dba_indexes where index_name='IDX_PAR_TAB_COL2';
select index_name,index_type, status from dba_indexes where index_name='IDX_PAR_TAB_COL3';
SYS@test>select index_name,index_type, status from dba_indexes where index_name='IDX_PAR_TAB_COL2';
INDEX_NAME INDEX_TYPE STATUS
------------------------------ --------------------------- --------
IDX_PAR_TAB_COL2 NORMAL N/A
SYS@test>select index_name,index_type, status from dba_indexes where index_name='IDX_PAR_TAB_COL3';
INDEX_NAME INDEX_TYPE STATUS
------------------------------ --------------------------- --------
IDX_PAR_TAB_COL3 NORMAL VALID
SYS@test>
查看执行计划
select * from part_tab where col2=10; -- 查看执行计划,虽然走了索引了。但是分区好像没有起作用,扫描从分区1到分区11 .
select * from part_tab where col2=10 and id=11; -- 查看执行计划,走了索引。分区从1到1 ,分区起作用了。
SYS@test>select * from part_tab where col2=10;
ID COL2 COL3
---------- ---------- ----------
9 10 11
Execution Plan
----------------------------------------------------------
Plan hash value: 2955748241
-----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 39 | 13 (0)| 00:00:01 | | |
| 1 | PARTITION RANGE ALL | | 1 | 39 | 13 (0)| 00:00:01 | 1 | 11 |
| 2 | TABLE ACCESS BY LOCAL INDEX ROWID| PART_TAB | 1 | 39 | 13 (0)| 00:00:01 | 1 | 11 |
|* 3 | INDEX RANGE SCAN | IDX_PAR_TAB_COL2 | 1 | | 12 (0)| 00:00:01 | 1 | 11 |
-----------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("COL2"=10)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
24 consistent gets
0 physical reads
0 redo size
658 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SYS@test>
--
SYS@test>select * from part_tab where col2=10 and id=11;
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 702898905
-----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 39 | 2 (0)| 00:00:01 | | |
| 1 | PARTITION RANGE SINGLE | | 1 | 39 | 2 (0)| 00:00:01 | 1 | 1 |
|* 2 | TABLE ACCESS BY LOCAL INDEX ROWID| PART_TAB | 1 | 39 | 2 (0)| 00:00:01 | 1 | 1 |
|* 3 | INDEX RANGE SCAN | IDX_PAR_TAB_COL2 | 1 | | 1 (0)| 00:00:01 | 1 | 1 |
-----------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("ID"=11)
3 - access("COL2"=10)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
462 bytes sent via SQL*Net to client
512 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
SYS@test>
再建立一个普通的表,和语句做对比 。对比发现,使用非分区表的时候,逻辑读是4 ,cost是2. 而使用分区表的时候,逻辑读是24,cost是13.
select * from part_tab where col2=10;
create table no_pat_tab tablespace users as select * from part_tab;
create index idx_no_part1 on no_pat_tab(col2) tablespace users;
select * from no_pat_tab where col2=10;
SYS@test>select * from no_pat_tab where col2=10;
ID COL2 COL3
---------- ---------- ----------
9 10 11
Execution Plan
----------------------------------------------------------
Plan hash value: 1274630437
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 39 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| NO_PAT_TAB | 1 | 39 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_NO_PART1 | 1 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("COL2"=10)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
4 consistent gets
0 physical reads
0 redo size
658 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SYS@test>
从上面的执行计划的对比,可以得出结论,当where查询条件里面没有分区条件的时候,分区表的效率不如普通表。
-- 下面测试分区表的索引问题。给分区表part_tab增加一个分区,查看各自索引的状态
alter table part_tab add partition p13 values less than(1000000);
insert into part_tab values (110000,110001,110002);
insert into part_tab values (120000,120001,120002);
insert into part_tab values (130000,130001,130002);
insert into part_tab values (140000,140001,140002);
commit;
--上面语句执行的时候报错ORA-14074: partition bound must collate higher than that of the last partition。需要处理下maxvalue的分区
--partition p11 values less than (maxvalue)
--partition p10 values less than (100000),
alter table part_tab split partition p11 at(200000) into (partition p12,partition p11); -- 有maxvalue要这样写
SYS@test>alter table part_tab split partition p11 at(200000) into (partition p12,partition p11); --将原来的最大的分区p11里的maxvalue 分割到p12分区。
Table altered.
SYS@test>
查看新增加的分区
SYS@test>select table_name,partition_name,high_value from dba_tab_partitions where table_name='PART_TAB';
TABLE_NAME PARTIT HIGH_VALUE
------------------------------ ------ --------------------------------------------------------------------------------
PART_TAB P1 10000
PART_TAB P10 100000
PART_TAB P11 MAXVALUE
PART_TAB P12 200000
PART_TAB P2 20000
PART_TAB P3 30000
PART_TAB P4 40000
PART_TAB P5 50000
PART_TAB P6 60000
PART_TAB P7 70000
PART_TAB P8 80000
TABLE_NAME PARTIT HIGH_VALUE
------------------------------ ------ --------------------------------------------------------------------------------
PART_TAB P9 90000
12 rows selected.
查看索引的状态。新增加的分区,对应的local索引和global索引都是有效的?(纳闷)
select index_name,partition_name,status from dba_ind_partitions where index_name='IDX_PAR_TAB_COL2';
select index_name,index_type, status from dba_indexes where index_name='IDX_PAR_TAB_COL3';
SYS@test>select index_name,partition_name,status from dba_ind_partitions where index_name='IDX_PAR_TAB_COL2';
INDEX_NAME PARTIT STATUS
------------------------------ ------ --------
IDX_PAR_TAB_COL2 P1 USABLE
IDX_PAR_TAB_COL2 P10 USABLE
IDX_PAR_TAB_COL2 P11 USABLE
IDX_PAR_TAB_COL2 P12 USABLE
IDX_PAR_TAB_COL2 P2 USABLE
IDX_PAR_TAB_COL2 P3 USABLE
IDX_PAR_TAB_COL2 P4 USABLE
IDX_PAR_TAB_COL2 P5 USABLE
IDX_PAR_TAB_COL2 P6 USABLE
IDX_PAR_TAB_COL2 P7 USABLE
IDX_PAR_TAB_COL2 P8 USABLE
INDEX_NAME PARTIT STATUS
------------------------------ ------ --------
IDX_PAR_TAB_COL2 P9 USABLE
12 rows selected.
SYS@test>select index_name,index_type, status from dba_indexes where index_name='IDX_PAR_TAB_COL3';
INDEX_NAME INDEX_TYPE STATUS
------------------------------ --------------------------- --------
IDX_PAR_TAB_COL3 NORMAL VALID
SYS@test>
--
select index_name,index_type, status from dba_indexes where index_name='IDX_PAR_TAB_COL2';
select index_name,index_type, status from dba_indexes where index_name='IDX_PAR_TAB_COL3';
truncate 一个分区,查看索引状态。 发现global 分区不可用了 。
alter table PART_TAB truncate partition p2;
SYS@test>select count(*) from part_tab partition (p2);
COUNT(*)
----------
0
SYS@test>select index_name,index_type, status from dba_indexes where index_name='IDX_PAR_TAB_COL2';
INDEX_NAME INDEX_TYPE STATUS
------------------------------ --------------------------- --------
IDX_PAR_TAB_COL2 NORMAL N/A
SYS@test>select index_name,index_type, status from dba_indexes where index_name='IDX_PAR_TAB_COL3';
INDEX_NAME INDEX_TYPE STATUS
------------------------------ --------------------------- --------
IDX_PAR_TAB_COL3 NORMAL UNUSABLE
SYS@test>
重新创建索引,在truncate分区的时候加上update global indexes, 发现truncate一个分区的数据后,索引状态不变。
create index idx_par_tab_col3 on part_tab(col3) tablespace users;
alter index idx_par_tab_col3 rebuild online;
SYS@test>select index_name,index_type, status from dba_indexes where index_name='IDX_PAR_TAB_COL3';
INDEX_NAME INDEX_TYPE STATUS
------------------------------ --------------------------- --------
IDX_PAR_TAB_COL3 NORMAL VALID
SYS@test>
alter table PART_TAB truncate partition p5 update global indexes;
SYS@test>alter table PART_TAB truncate partition p5 update global indexes;
Table truncated.
SYS@test>select count(*) from part_tab partition (p5);
COUNT(*)
----------
0
SYS@test>select index_name,index_type, status from dba_indexes where index_name='IDX_PAR_TAB_COL3';
INDEX_NAME INDEX_TYPE STATUS
------------------------------ --------------------------- --------
IDX_PAR_TAB_COL3 NORMAL VALID
SYS@test>
再次测试,drop掉一个分区,global分区索引状态会变化。而local分区索引状态不会变化。
create table t1 (id int,col2 int,col3 int) tablespace users
partition by range(id)
(
partition p1 values less than (10000),
partition p2 values less than (20000),
partition p3 values less than (30000),
partition p4 values less than (40000),
partition p5 values less than (50000),
partition p6 values less than (60000),
partition p7 values less than (70000),
partition p8 values less than (80000),
partition p9 values less than (90000),
partition p10 values less than (100000),
partition p11 values less than (110000)
);
-- 插入数据
insert into t1 select rownum,rownum+1,rownum+2 from dual connect by rownum<110000;
commit;
-- 在col2上建立局部索引
create index idx_t1_local on t1(col2) local tablespace users;
-- 在col3 上建立全局索引
create index idx_t1_global on t1(col3) tablespace users;
alter table t1 drop partition p5;
SYS@test>select index_name,partition_name,status from dba_ind_partitions where index_name='IDX_T1_LOCAL';
INDEX_NAME PARTIT STATUS
------------------------------ ------ --------
IDX_T1_LOCAL P1 USABLE
IDX_T1_LOCAL P10 USABLE
IDX_T1_LOCAL P11 USABLE
IDX_T1_LOCAL P12 USABLE
IDX_T1_LOCAL P2 USABLE
IDX_T1_LOCAL P3 USABLE
IDX_T1_LOCAL P4 USABLE
IDX_T1_LOCAL P6 USABLE
IDX_T1_LOCAL P7 USABLE
IDX_T1_LOCAL P8 USABLE
IDX_T1_LOCAL P9 USABLE
11 rows selected.
SYS@test>select index_name,status from dba_indexes where index_name='IDX_T1_GLOBAL';
INDEX_NAME STATUS
------------------------------ --------
IDX_T1_GLOBAL UNUSABLE
从上面的测试,得出结论,当索引为local 索引的时候,对分区做操作,索引状态不会改变,当索引为global索引的时候,新增加分区,索引状态不变,drop分区或者
truncate分区的数据后,索引状态会改变。加上update global indexes可以避免。
END