Oracle 表分区
1 内容简介:
1.1创建分区表;
1.2 分区查询、截取
1.3.添加分区;
1.4.删除分区;
1.5.表分区交换;
1.6.表分区折分;
1.7.表分区合并;
1.8.表分区移动;
内容(以下测试均采用范围分区):
1.1 创建分区表:
CREATE TABLE TPART
(
ID NUMBER,
NAME VARCHAR2(30),
GENDER CHAR(2),
IDCARD VARCHAR2(18),
HOMEADDR VARCHAR2(2000),
EMAIL VARCHAR2(50),
MOBILEPHONE VARCHAR2(11),
BIRTHDATE DATE,
EDITDATE DATE
)
PARTITION BY RANGE(EDITDATE)
(
PARTITION PART_TPAT1 VALUES LESS THAN(TO_DATE('2014-02-01','YYYY-MM-DD')) TABLESPACE TBS03,
PARTITION PART_PART2 VALUES LESS THAN(TO_DATE('2014-03-01','YYYY-MM-DD')) TABLESPACE TBS03
);
--注意,创建分区表时请分析是否需要创建最大分区,创建最大分区后以后需要添加分区时必须先删除最大分区然后在添加;
1.2 分区查询、截取:
1.2.1 查询 tpart 表 tpart_part_part1 分区数据总数:
SQL> SELECT COUNT(*) FROM TPART PARTITION(TPART_PART_PART1);
COUNT(*)
----------
199999
1.2.2 查询 tpart表 tpart_part_part1分区 name='sywu'的数据:
SQL> SELECT * FROM TPART PARTITION(TPART_PART_PART1) WHERE NAME='SYWU';
Elapsed: 00:00:00.07
Execution Plan
----------------------------------------------------------
Plan hash value: 4266250980
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 60 | 127 (0)| 00:00:02 | | |
| 1 | PARTITION RANGE SINGLE| | 1 | 60 | 127 (0)| 00:00:02 | 1 | 1 |
|* 2 | TABLE ACCESS FULL | TPART | 1 | 60 | 127 (0)| 00:00:02 | 1 | 1 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("NAME"='sywu')
Statistics
----------------------------------------------------------
3086 recursive calls
0 db block gets
1992 consistent gets
1421 physical reads
0 redo size
883 bytes sent via SQL*Net to client
508 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
56 sorts (memory)
相比普通查询,在未建立索引的情况下,指定分区查询时数据库直接定位到该分区检索数据,避免了扫描表包含的所有分区;
1.2.3 分区截取:
SQL> ALTER TABLE TPART TRUNCATE PARTITION TPART_PART3;
Table truncated.
Elapsed: 00:00:00.32
截取分区后,对于本地分区索引不受影响,非本地分区索引因为截取分区导致表中的行(ROWID)发生了变化,Oracle无法判断哪些行被删除了,索引存储的行(ROWID)依旧是旧的,索引状态将被置为不可用(UNUSABLE):
SQL> SELECT TABLE_NAME,INDEX_NAME,STATUS FROM USER_INDEXES WHERE TABLE_NAME='TPART';
TABLE_NAME INDEX_NAME STATUS
------------------------------ ------------------------------ --------
TPART IND_TPART N/A
TPART ID_TPART_ID UNUSABLE
Elapsed: 00:00:00.06
1.3 添加分区:
新添加的分区必须是大于当前分区中最大分区的;如果已经存在最大分区(MAXVALUE)将无法再添加,必须删除后再添加;
SQL> ALTER TABLE TPART ADD PARTITION TPART_PART3 VALUES LESS THAN(TO_DATE('2014-04-01','YYYY-MM-DD')) TABLESPACE TBS03;
Table altered.
Elapsed: 00:00:00.17
相关错误:(ORA-14074: partition bound must collate higher than that of the last partition)
1.4 删除分区:
SQL> ALTER TABLE TPART DROP PARTITION TPART_PART3;
Table altered.
Elapsed: 00:00:00.22
删除分区后,对于本地分区索引不受影响,非本地分区索引状态将被置为不可用(UNUSABLE);
1.5分区交换:
用来与分区交换的表结构必须与分区表一致,对于范围分区,待交换的数据范围最大值不能超过指定分区最大值;如果待交换的数据中有值范围存在于另一个分区且小于或大于当前分区,则不允许交换;
如果交换包含索引则分区表和交换表必须具有相同索引列且分区表索引必须是本地分区索引(相关错误:ORA-14098: index mismatch for tables in ALTER TABLE EXCHANGE PARTITION)
1.5.1不带索引的分区交换:
SQL> ALTER TABLE TPART EXCHANGE PARTITION TPART_PART1
2 WITH TAble temp_tpart;
Table altered.
Elapsed: 00:00:00.08
交换结束后,与分区交换的表索引状态会被置为不可用(UNUSABLE):
SQL> SELECT TABLE_NAME,INDEX_NAME,STATUS FROM USER_INDEXES WHERE TABLE_NAME='TEMP_TPART';
TABLE_NAME INDEX_NAME STATUS
------------------------------ ------------------------------ --------
TEMP_TPART IND_TEMP_TPART UNUSABLE
Elapsed: 00:00:00.03
分区表交换的分区索引也会置为UNUSABLE:
SQL> SELECT INDEX_NAME,PARTITION_NAME,STATUS FROM USER_IND_PARTITIONS WHERE INDEX_NAME='IND_TPART';
INDEX_NAME PARTITION_NAME STATUS
------------------------------ ------------------------------ --------
IND_TPART TPART_PART1 UNUSABLE
IND_TPART TPART_PART2 USABLE
IND_TPART TPART_PART3 USABLE
Elapsed: 00:00:00.02
重建分区不可用索引:
ALTER TABLE TPART MODIFY PARTITION TPART_PART1 REBUILD UNUSABLE LOCAL INDEXES;
注:如果交换的分区表上有非本地分区索引,分区交换结束后索引状态都会被置为不可用(UNUSABLE);
1.5.2 带索引的分区交换:
SQL> ALTER TABLE TPART EXCHANGE PARTITION TPART_PART1
2* WITH TABLE TEMP_TPART INCLUDING INDEXES;
Table altered.
Elapsed: 00:00:00.09
对于带索引的分区交换,交换结束后需要更新统计信息;不影响本地分区索引;如果分区表中有非本地分区索引,分区交换结束后索引状态都会被置为不可用(UNUSABLE);
1.6 表分区拆分:
表分区拆分需要指定拆分的分区、时间截;Oracle 会根据指定的时间截匹配每一行,以下测试将表 TPART 的表分区 TPART_PART1 中的2013-08-01以前的数据拆分到新分区 TPART_PART_201308 中:
SQL> ALTER TABLE TPART SPLIT PARTITION TPART_PART1
2 AT (TO_DATE('2013-08-01','YYYY-MM-DD'))
3 INTO (
4 PARTITION TPART_PART_201308 TABLESPACE TBS03,
5 PARTITION TPART_PART1
6 );
Table altered.
Elapsed: 00:00:01.83
Oracle 会自动创建新的分区 (TPART_PART_201308),对于新分区和拆分的分区索引状态将被置为不可用(UNUSABLE);
SQL> SELECT INDEX_NAME,PARTITION_NAME,HIGH_VALUE,STATUS FROM USER_IND_PARTITIONS WHERE INDEX_NAME='IND_TPART';
INDEX_NAME PARTITION_NAME HIGH_VALUE STATUS
------------------------------ ------------------------------ ------------------------------ --------
IND_TPART TPART_PART1 TO_DATE(' 2014-02-01 00:00:00' UNUSABLE
IND_TPART TPART_PART2 TO_DATE(' 2014-03-01 00:00:00' USABLE
IND_TPART TPART_PART3 TO_DATE(' 2014-03-02 00:00:00' USABLE
IND_TPART TPART_PART_201308 TO_DATE(' 2013-08-01 00:00:00' UNUSABLE
Elapsed: 00:00:00.03
其它的本地分区索引不受影响;如果表中存在非本地分区索引,索引的状态将被置为不可用(UNUSABLE):
SQL> SELECT TABLE_NAME,INDEX_NAME,INDEX_TYPE,STATUS FROM USER_INDEXES WHERE TABLE_NAME='TPART';
TABLE_NAME INDEX_NAME INDEX_TY STATUS
------------------------------ ------------------------------ -------- --------
TPART IND_TPART NORMAL N/A
TPART IND_TPART_NAME NORMAL UNUSABLE
TPART ID_TPART_ID NORMAL UNUSABLE
Elapsed: 00:00:00.00
1.7 表分区合并:
合并表分区需要指定合并的表分区和合并后的新分区名,指定分区时必须先指定最小(下界)分区;相关错误(ORA-14273: 必须首先指定下界分区);以下测试将 TPART 表的分区:TPART_PART_201308 (下界)、TPART_PART1 (上界)合并为TPART_PART_MERGE :
SQL>ALTER TABLE TPART MERGE PARTITIONS TPART_PART_201308,TPART_PART1
2* INTO PARTITION TPART_PART_MERGE TABLESPACE TBS03;
Table altered.
Elapsed: 00:00:01.91
对于合并分区,Oracle 会删除需合并的分区并以合并前最大(上界)分区的最大值(HIGH_VALUE)创建新的分区:
SQL> SELECT INDEX_NAME,PARTITION_NAME,HIGH_VALUE,STATUS FROM USER_IND_PARTITIONS WHERE INDEX_NAME='IND_TPART';
INDEX_NAME PARTITION_NAME HIGH_VALUE STATUS
------------------------------ ------------------------------ ------------------------------ --------
IND_TPART TPART_PART2 TO_DATE(' 2014-03-01 00:00:00' USABLE
IND_TPART TPART_PART3 TO_DATE(' 2014-03-02 00:00:00' USABLE
IND_TPART TPART_PART_MERGE TO_DATE(' 2014-02-01 00:00:00' UNUSABLE
Elapsed: 00:00:00.14
合并分区后,对于合并后的新分区索引状态将被置为不可用(UNUSABLE);如果所操作的分区表中有非本地分区索引则状态将被置为不可用(UNUSABLE):
SQL> SELECT TABLE_NAME,INDEX_NAME,INDEX_TYPE,STATUS FROM USER_INDEXES WHERE TABLE_NAME='TPART';
TABLE_NAME INDEX_NAME INDEX_TY STATUS
------------------------------ ------------------------------ -------- --------
TPART IND_TPART NORMAL N/A
TPART IND_TPART_NAME NORMAL UNUSABLE
TPART ID_TPART_ID NORMAL UNUSABLE
Elapsed: 00:00:00.02
1.8 表分区移动:
SQL> ALTER TABLE TPART MOVE PARTITION TPART_PART_MERGE;
Table altered.
Elapsed: 00:00:00.88
或将表分区移动到别的表空间:
SQL> ALTER TABLE TPART MOVE PARTITION TPART_PART_MERGE TABLESPACE TBS02;
Table altered.
Elapsed: 00:00:02.06
对于表分区移动,所移动的本地分区索引将被置为不可用(UNUSABLE);如果所操作的分区表中有非本地分区索引则状态将被置为不可用(UNUSABLE):
测试版本:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
PL/SQL Release 11.2.0.1.0 – Production
CORE 11.2.0.1.0 Production
TNS for Linux: Version 11.2.0.1.0 – Production
NLSRTL Version 11.2.0.1.0 – Production
总结:
在索引存储结构中,索引存储(ROWID和相关索引列的值),如果查询索引列,优化器通过扫描索引获得索引中存储的值,无须再扫描访问表;如果查询中需要查询除索引列以外的列,则优化器分析获取数据的成本,选用最低成本获取数据;使用索引时,数据库扫描索引获取ROWID,然后通过ROWID定位到表行;ROWID由:Data object id(前六位字符)、Relative file Number (3位)、Block number(6位)、Row number(3位) 64进制组成,当分区数据移动、交换、折分、合并时,表行(ROWID)发生变化,索引存储的ROWID不在可用,需要更新ROWID;对于非本地分区索引(全局索引、B-TREE、BITMAP ..)因为表中的某些行被移动、删除,但索引未随之更新,同样需要更新ROWID;
重建非本地分区索引:
SQL> ALTER INDEX IND_TPART2_NAME REBUILD TABLESPACE TBS03 PARALLEL 10 COMPUTE STATISTICS;
Index altered.
Elapsed: 00:00:03.70
重建本地分区索引因为考虑分区的数量,可删除后重新建立,另一种方式是只重建不可用的分区索引(如下所示):
SQL> ALTER TABLE TPART2 MODIFY PARTITION TPART2_PART1 REBUILD UNUSABLE LOCAL INDEXES;
Table altered.
Elapsed: 00:00:00.45
此种方式重建相比删除后重新建要快,可以使用并行的方式创建。