读书人

oracle 分区表的建立方体法

发布时间: 2012-09-08 10:48:07 作者: rapoo

oracle 分区表的建立方法

Oracle提供了分区技术以支持VLDB(Very Large DataBase)。分区表通过对分区列的判断,把分区列不同的记录,放到不同的分区中。分区完全对应用透明。

?

Oracle的分区表可以包括多个分区,每个分区都是一个独立的段(SEGMENT),可以存放到不同的表空间中。查询时可以通过查询表来访问各个分区中的数据,也可以通过在查询时直接指定分区的方法来进行查询。

?

分区提供以下优点:?

?

由于将数据分散到各个分区中,减少了数据损坏的可能性;?

?

可以对单独的分区进行备份和恢复;?

?

可以将分区映射到不同的物理磁盘上,来分散IO;

?

提高可管理性、可用性和性能。?

?

Oracle提供了以下几种分区类型:

?

范围分区(range);

?

哈希分区(hash);

?

列表分区(list);

?

范围-哈希复合分区(range-hash);

?

范围-列表复合分区(range-list)。

Oracle的在线重定义表功能(二):http://blog.itpub.net/post/468/12962

?

?

索引也可以进行分区,分区索引有两种类型:global和local。对于local索引,每一个表分区对应一个索引分区,当表的分区发生变化时,索引的维护由Oracle自动进行。对于global索引,可以选择是否分区,而且索引的分区可以不与表分区相对应。当对分区进行维护操作时,通常会导致全局索引的INVALDED,必须在执行完操作后REBUILD。Oracle9i提供了UPDATE GLOBAL INDEXES语句,可以使在进行分区维护的同时重建全局索引。

全局索引可以包含多个分区的值 局部索引比全局索引容易管理,而全局索引比较快
注意:不能为散列分区 或者 子分区创建全局索引

?

Oracle的分区功能十分强大。不过用起来发现有两点不大方便:

?

第一是已经存在的表没有方法可以直接转化为分区表。不过Oracle提供了在线重定义表的功能,可以通过这种方式来完成普通表到分区表的转化。可以参考这个例子:http://blog.itpub.net/post/468/13091

?

第二点是如果采用了local分区索引,那么在增加表分区的时候,索引分区的表空间是不可控制的。如果希望将表和索引的分区分开到不同的表空间且不同索引分区也分散到不同的表空间中,那么只能在增加分区后,对新增的分区索引单独rebuild。

Oracle最大允许存在多少个分区呢?

我们可以从Oracle的Concepts手册上找到这个信息,对于Oracle9iR2:

Tables can be partitioned into up to 64,000 separate partitions.

对于Oracle10gR2,Oracle增强了分区特性:

Tables can be partitioned into up to 1024K-1 separate partitions.

关于何时应该进行分区,Oracle有如下建议:

■ Tables greater than 2GB should always be considered for partitioning.
■ Tables containing historical data, in which new data is added into the newest partition. A typical example is a historical table where only the current month's data is updatable and the other 11 months are read only.

==========================================================================================

首先,建立分区表。

?

CREATE TABLE MALS_NM_CPU_INFO_T_NEW
(
? HOST_IP??????? VARCHAR2(40 BYTE)????????????? NOT NULL,
? HOST_NAME????? VARCHAR2(15 BYTE)????????????? NOT NULL,
? COMMIT_TM????? VARCHAR2(14 BYTE)????????????? NOT NULL,
? SYS_ID???????? VARCHAR2(32 BYTE)????????????? NOT NULL,
? CPU_FREQUENCY? NUMBER(10),
? CPU_LOAD?????? NUMBER(3)
)
PARTITION BY RANGE (COMMIT_TM)? --以COMMIT_TM字段做分区条件
(PARTITION P_NM_CPU_INFO_20081120 VALUES LESS THAN ('20081121'));

?

若是已经建立了表,但是却没有分区,就只能根据已经有的表新建分区表了,如下:

?

CREATE TABLE MALS_NM_CPU_INFO_T_NEW
(
? HOST_IP??????? VARCHAR2(40 BYTE)????????????? NOT NULL,
? HOST_NAME????? VARCHAR2(15 BYTE)????????????? NOT NULL,
? COMMIT_TM????? VARCHAR2(14 BYTE)????????????? NOT NULL,
? SYS_ID???????? VARCHAR2(32 BYTE)????????????? NOT NULL,
? CPU_FREQUENCY? NUMBER(10),
? CPU_LOAD?????? NUMBER(3)
)
PARTITION BY RANGE (COMMIT_TM)
(PARTITION P_NM_CPU_INFO_20081120 VALUES LESS THAN ('20081121'));

insert into MALS_NM_CPU_INFO_T_NEW select * from MALS_NM_CPU_INFO_T;

rename MALS_NM_CPU_INFO_T to MALS_NM_CPU_INFO_T_old;

rename MALS_NM_CPU_INFO_T_new to MALS_NM_CPU_INFO_T;

create index nm_cpu_info_index on MALS_NM_CPU_INFO_T(Commit_Tm);? --建立局部分区索引,默认与当前表分区,在一个表空间中

?

此时建立完表,在TOAD中会在表旁边看见分区图标

?

其次,建立增加分区的存储过程。

?

CREATE OR REPLACE PROCEDURE MALS_NM_ADD_PARTITION_PROC(
?partNum? NUMBER,? --添加分区的个数
?TableSpaceName VARCHAR2 --分区名
) AS
?v_SqlExec VARCHAR2(2000); --DDL语句变量
?v_PartDate VARCHAR2(20); --创建分区的日期(YYYYMMDD)
?v_PartDate1 VARCHAR2(20); --创建分区的日期(YYYYMMDD)
?v_err_num? NUMBER;? --ORA错误号
?v_err_msg? VARCHAR2(100); --错误描述

?v_cpu_info_max VARCHAR2(20); --mals_nm_cpu_info_t 表分区的最大日期

?

BEGIN
--查询已创建 mals_nm_cpu_info_t 表分区的最大日期
--P_NM_CPU_INFO_20080221
select max(SUBSTR(partition_name,15,8)) into v_cpu_info_max
from user_tab_partitions
WHERE table_name=UPPER('MALS_NM_CPU_INFO_T');

?FOR i IN 1..partNum LOOP

? --创建 mals_nm_cpu_info_t 表分区
? IF v_cpu_info_max<to_char(sysdate+i,'yyyymmdd') THEN
? v_PartDate:=to_char(SYSDATE+i,'YYYYMMDD');
? v_PartDate1:=to_char(SYSDATE+i+1,'YYYYMMDD');
? v_SqlExec:='ALTER TABLE MALS_NM_CPU_INFO_T ADD PARTITION P_NM_CPU_INFO_' || v_PartDate ||
?? ' values less than(''' || v_PartDate1 || '000000'') TABLESPACE ' ||
?? TableSpaceName;
? dbms_output.put_line('创建 mals_nm_cpu_info_t 表分区' || i || '='||v_SqlExec);
? DBMS_Utility.Exec_DDL_Statement(v_SqlExec);
? END IF;

?END LOOP;
EXCEPTION
?WHEN OTHERS THEN
? v_err_num := SQLCODE;
? v_err_msg := SUBSTR(SQLERRM, 1, 100);
? dbms_output.put_line('MALS_NM_ADD_PARTITION_PROC执行出现异常,错误码='|| v_err_num || '错误描述=' || v_err_msg);
END MALS_NM_ADD_PARTITION_PROC;

?

再次,建立删除分区的存储过程

?

CREATE OR REPLACE PROCEDURE MALS_NM_DROP_PARTITION_PROC(
?beforeDays NUMBER? --删除多少天前的分区
)
As
?v_SqlExec? VARCHAR2(2000); --DDL语句变量
?v_err_num? NUMBER;? --ORA错误号
?v_err_msg? VARCHAR2(100); --错误描述

?--查找beforeDays天前存在的 mals_nm_cpu_info_t 表分区
?cursor cursor_cpu_info_part is
?select partition_name from user_tab_partitions
?WHERE table_name=UPPER('MALS_NM_CPU_INFO_T')
?AND SUBSTR(partition_name,15,8)<TO_CHAR(SYSDATE-beforeDays,'YYYYMMDD')
?ORDER BY partition_name;
?record_cpu_info_oldpart cursor_cpu_info_part%rowType;

BEGIN
?open cursor_cpu_info_part;
? loop
?? fetch cursor_cpu_info_part into record_cpu_info_oldpart;
?? exit when cursor_cpu_info_part%notfound;
?? --删除 mals_nm_cpu_info_t 表分区
?? v_SqlExec:='ALTER TABLE MALS_NM_CPU_INFO_T DROP PARTITION ' ||
?? record_cpu_info_oldpart.partition_name;
?? dbms_output.put_line('删除mals_nm_cpu_info_t表分区='||v_SqlExec);
?? DBMS_Utility.Exec_DDL_Statement(v_SqlExec);
? end loop;
?close cursor_cpu_info_part;

EXCEPTION
?WHEN OTHERS THEN
? v_err_num := SQLCODE;
? v_err_msg := SUBSTR(SQLERRM, 1, 100);
? dbms_output.put_line('MALS_NM_DROP_PARTITION_PROC执行出现异常,错误码='|| v_err_num || '错误描述=' || v_err_msg);
END MALS_NM_DROP_PARTITION_PROC;

?

然后,建立两个执行增加、删除分区的存储过程

?

执行增加的存储过程:

CREATE OR REPLACE PROCEDURE MALS_NM_EXEC_ADD_PROC AS
??? v_err_num? NUMBER;? --ORA错误号
?? v_err_msg? VARCHAR2(100); --错误描述
BEGIN
?--10代表创建10天的分区,tablespace代表表空间名
?MALS_NM_ADD_PARTITION_PROC(10,'tablespace');
?COMMIT;
EXCEPTION
?WHEN OTHERS THEN
? v_err_num := SQLCODE;
? v_err_msg := SUBSTR(SQLERRM, 1, 100);
? dbms_output.put_line('MALS_NM_DROP_PARTITION_PROC执行出现异常,错误码='|| v_err_num || '错误描述=' || v_err_msg);
END MALS_NM_EXEC_ADD_PROC;

?

执行删除的存储过程:

CREATE OR REPLACE PROCEDURE MALS_NM_EXEC_DROP_PROC AS
??? v_err_num? NUMBER;? --ORA错误号
?? v_err_msg? VARCHAR2(100); --错误描述
BEGIN
?--删除3个月前的数据 100代表100天
?MALS_NM_DROP_PARTITION_PROC(100);
?COMMIT;
EXCEPTION
?WHEN OTHERS THEN
? v_err_num := SQLCODE;
? v_err_msg := SUBSTR(SQLERRM, 1, 100);
? dbms_output.put_line('MALS_NM_DROP_PARTITION_PROC执行出现异常,错误码='|| v_err_num || '错误描述=' || v_err_msg);
END MALS_NM_EXEC_DROP_PROC;

?

建立完以上四个存储过程若是发现某个存储过程前有一个红叉,刚说明存在语法错误,此时若是在PL/SQL中可以进入该存储过程,按F8进行编译,控制台会看见相应错误信息的提示,若是在TOAD中可以在存储过程中点击右键,选择“compile”即可开始调试。

?

最后,建立JOB定时执行存储过程

?

create or replace procedure MALS_NM_JOBS_PROC as
??? job1 number;? --每天1点创建分区
??? job2 number;? --每天3点删除分区
???
??? v_err_num? NUMBER;? --ORA错误号
?? v_err_msg? VARCHAR2(100); --错误描述

begin
?dbms_job.submit(job1,'MALS_NM_EXEC_ADD_PROC;',sysdate,'TRUNC(SYSDATE+1) + (1*60)/(24*60)');
?dbms_job.submit(job2,'MALS_NM_EXEC_DROP_PROC;',sysdate,'TRUNC(SYSDATE+1) + (3*60)/(24*60)');
?commit;

EXCEPTION
?WHEN OTHERS THEN
? v_err_num := SQLCODE;
? v_err_msg := SUBSTR(SQLERRM, 1, 100);
? dbms_output.put_line('MALS_NM_DROP_PARTITION_PROC执行出现异常,错误码='|| v_err_num || '错误描述=' || v_err_msg);
end?? MALS_NM_JOBS_PROC;

建立完这个存储过程后,就可以运行这个存储过程以达到我们定时删除、增加分区的功能

?

在运行了这个存储过程之后,如果一切正常在PL/SQL或TOAD下刷新,则会在JOB中发现两个新建立的JOB。

?

若是没有发现新的JOB则说明建立的某个存储过程虽然编译通过但是在执行中仍有问题,此时我们就要对建立的

存储过程进行DEBUG了(在PL/SQL中)。

?

首先,在存储过程中感觉存在问题的地方打上断点(CTRL+B);

其次,右键单击存储过程,选择“Test”;

然后,在弹出的Test windows窗口的下方,为我们的存储过程,填写所需要的参数;

再次,点击窗口左上角的图标,或直接按F9,进入调试窗口,开始调试。

?

还要记得,要调试,必须具有调试的权限,否则需要用管理员用户赋予权限

grant Debug Connect Session to user

?

为了在系统测试或现网环境中确认我们的代码是否正常工作时,还可以记录log。plsql提供了一个utl_file包,通过定义utl_file包中的file_type类型,能够获得一个文档句柄,通过此句柄能够实现一般的文档操作功能。

?

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/imasmallbird/archive/2008/11/20/3340547.aspx

读书人网 >其他数据库

热点推荐