分区表的执行计划 与 索引

创建分区表

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 

猜你喜欢

转载自blog.csdn.net/xxzhaobb/article/details/80973445
今日推荐