作为一个成熟的DBMS,在每个新的版本中Oracle都会推出一些有益的技术尝试和新特性。熟悉掌握这些新特性,有助于我们更快的适应新版本Oracle软件,掌握其发展动态脉络,及时优化我们的工作方式。
分区表是我们经常使用的一种堆表优化手段。借助分区表,我们可以将一个数据量巨大的表根据业务需求水平切分为不同的分区块。将数据访问处理和运维管理集中在特定的数据块内部,以期减少全表大面积搜索。
相对于普通数据表,分区表要花很多的规划和管理精力。规划包括分区类型的选择、分区键选择和物理段segment存储分配。管理包括分区预留和添加、对应分区数据管理等等。
在Oracle11g之前,分区表包括多少个分区,各分区都在什么位置上是在建表过程中确定的。之后的修改需要手工完成。Oracle11g推出了间距Interval-Partition的特性,实现一些类型分区表的自动分区管理。
1、Before Oracle11g
首先,我们来看看Interval-Partition出现之前的特性。Oracle DBA和开发人员对分区表通常是需要进行预分区规划,也就是在部署系统的时候就预先建立出一些预留分区(通常出现在数字类型和日期类型,比如预先分配3年系统的数据分区)。因为如果数据表建立,特别是生产环境上的数据表建立,新增加和划分分区就有很多维护窗口问题,所以DBA经常对数据表进行预先分区。
在11g之前,如果数据中出现未能匹配分区条件的情况,系统会拒绝进行数据操作。
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database10gEnterpriseEdition Release10.2.0.1.0 - Prod
PL/SQL Release10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for 32-bit Windows: Version10.2.0.1.0 - Production
NLSRTL Version10.2.0.1.0 - Production
我们构建一个简单的Range-Partition Table。
SQL> create table t_part
2 (
3 EMPNO NUMBER(4) not null,
4 ENAME VARCHAR2(10),
5 JOB VARCHAR2(9),
6 MGR NUMBER(4),
7 HIREDATE DATE,
8 SAL NUMBER(7,2),
9 COMM NUMBER(7,2),
10 DEPTNO NUMBER(2)
11 )
12 partition by range(sal)
13 (
14 partition t_p1 values less than (1000) tablespace users,
15 partition t_p2 values less than (2000) tablespace system,
16 partition t_p3 values less than (3000) tablespace mytest
17 );
Table created
如果此时试图插入数据,对未能映射到分区的数据是报错提示的。
SQL> insert into t_part select * from scott.emp;
insert into t_part select * from scott.emp
ORA-14400:插入的分区关键字未映射到任何分区
SQL> select count(*) from scott.emp wheresal>=3000;
COUNT(*)
----------
3
结论:在Interval-Partition特性出现之前,DBA必须预先对将来可能出现的数据值进行规划或者预测。如果是一个生产系统,Online状态添加或者修改分区存在一些操作风险。
2、Interval-Partition feature
在Oracle11g中,推出了Interval-Partition的新特性。Interval-Partition特性并不是提供了一种新的分区方案,而是提供了一种分区拓展方案。下面我们通过一个实验来演示Interval-Partition的使用。
SQL> select * from v$version;
BANNER
-------------------------------------------------------------------
Oracle Database11gEnterpriseEdition Release11.2.0.1.0 - Production
PL/SQL Release11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
TNS for Linux: Version11.2.0.1.0 - Production
NLSRTL Version11.2.0.1.0–Production
此时我们选择Oracle 11r2版本进行试验。
SQL> create table t_part
2 (
3 EMPNO NUMBER(4) not null,
4 ENAME VARCHAR2(10),
5 JOB VARCHAR2(9),
6 MGR NUMBER(4),
7 HIREDATE DATE,
8 SAL NUMBER(7,2),
9 COMM NUMBER(7,2),
10 DEPTNO NUMBER(2)
11 )
12 partition by range(sal)
13interval (1000)
14 store in (users, system)
15 (
16 partition t_p1 values less than (1000),
17 partition t_p2 values less than (2000),
18 partition t_p3 values less than (3000)
19 );
Table created
我们构建了一个和Oracle10g实验基本类似的环境。分区表分区键和分区类型相同,唯一较大的差异在于中间添加了子句Interval(1000)。在Oracle中,分区��对应的数据段是多个,我们通过视图dba_segments可以查看到特性信息。
SQL> select table_name, partition_name, high_value, PARTITION_POSITION, TABLESPACE_NAME from dba_tab_partitions where table_name='T_PART';
TABLE_NAME PARTITION_NAME HIGH_VALUE PARTITION_POSITION TABLESPACE_NAME
---------- -------------------- ---------- ------------------ ------------------------------
T_PART T_P1 1000 1 SYSTEM
T_PART T_P2 2000 2 SYSTEM
T_PART T_P3 3000 3 SYSTEM
包括了在定义数据表时确定的三个数据段,符合条件的映射值分别为1000、2000和3000。我们对分区表可以使用dbms_stats方法进行适当的统计量收集。
SQL> exec dbms_stats.gather_table_stats(user,'T_PART',cascade => true);
PL/SQL procedure successfully completed
SQL> select table_name, partition_name, high_value, PARTITION_POSITION, TABLESPACE_NAME, num_rows from dba_tab_partitions where table_name='T_PART';
TABLE_NAME PARTITION_NAME HIGH_VALUE PARTITION_POSITION NUM_ROWS
---------- -------------------- ---------- ------------------ ----------
T_PART T_P1 1000 1 0
T_PART T_P2 2000 2 0
T_PART T_P3 3000 3 0
接下来,向数据表t_part中灌入数据scott.t。
SQL> insert into t_part select * from scott.emp;
14 rows inserted
SQL> commit;
Commit complete
SQL> select * from scott.emp;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
7566 JONES MANAGER 78391981/4/2 2975.00 20
7788 SCOTT ANALYST 75661987/4/19 3000.00 20
7839 KING PRESIDENT 1981/11/17 5000.00 10
(篇幅原因,有省略……)
7902 FORD ANALYST 75661981/12/3 3000.00 20
7934 MILLER CLERK 77821982/1/23 1300.00 10
14 rows selected
注意:插入的数据中包括了大于等于3000的数据值,但是还是成功插入到了分区表中。我们检查分区表段情况。
SQL> exec dbms_stats.gather_table_stats(user,'T_PART',cascade => true);
PL/SQL procedure successfully completed
SQL> select table_name, partition_name, high_value, PARTITION_POSITION, TABLESPACE_NAME, num_rows from dba_tab_partitions where table_name='T_PART';
TABLE_NAME PARTITION_NAME HIGH_VALUE PARTITION_POSITION TABLESPACE_NAME NUM_ROWS
---------- -------------------- ---------- ------------------ -------------------- ----------
T_PART T_P1 1000 1 SYSTEM 2
T_PART T_P2 2000 2 SYSTEM 6
T_PART T_P3 3000 3 SYSTEM 3
T_PART SYS_P21 4000 4 SYSTEM 2
T_PART SYS_P22 6000 5 SYSTEM 1
注意:原有的三个数据段变成了五个数据段。出现了两个新的分区段sys_p21和sys_p22,分别对应Range分区上线4000和6000。统计值中表明插入的三个异常值存在于其内。
这样我们就能够明白interval-partition在Range分区数字类型分区键的作用了。简单的说,在定义分区表的时候,可以通过interval指定出一个分区拓展的规则方案。在例子中,我们选择了sal变化1000的时候,进行拓展分区。之后,当Oracle在对这个数据表进行操作的时候,如果发生了超过原有分区范围的情况,会按照1000的步长进行自动的分区建立。
例子中,我们有3000、3000和5000的异常值。两个3000拓展为以4000作为less than的分区。5000的异常值自然拓展为以6000为less than的分区。
数字类型分区键的interval分区在应对异常数据值和新增数据值可能的时候效果很好。Interval-Partition是在原有分区的基础上,提供异常值分区拓展方法。同时这样对一些有规则的分区拓展,就可以实现Oracle自动进行新分区的加入了。
目前,Oracle11g支持两种类型的分区键进行Interval-Partition,number类型和date类型。下面我们对date日期类型变量的拓��分区使用进行试验演示。