分区表
通过本章节的学习,您可以学到以下几个问题
1、 了解分区表的概念
2、 清楚分区表的用途
3、 了解分区表的分类
4、 了解分区表的操作
在我们使用普通表的过程中会有数据量特别大的表,当一个表的数据超过过2000万条或占用2G空间时,建议建立分区表
分区表的分类:
Range(范围)分区
Hash(哈希)分区
List(列表)分区
以及组合分区:Range-Hash,Range-List
分区的优点:
增强可用性:如果表的某个分区出现故障,表在其他分区的数据仍然可用;
维护方便:如果表的某个分区出现故障,需要修复数据,只修复该分区即可;
均衡I/O:可以把不同的分区映射到磁盘以平衡I/O,改善整个系统性能;
改善查询性能:对分区对象的查询可以仅搜索自己关心的分区,提高检索速度。
执行概要
分区功能可以提高许多应用程序的可管理性、性能与可用性。通过分区功能,可以将表、索引和索引组织表进一步细分为段,从而能够更精确地管理和访问这些数据库对象。Orac#提供了种类繁多的分区方案以满足每种业务要求。而且,因为sql语句中分区是完全透明的,所以该功能几乎可应用于任何应用程序。
分区功能的优势
分区功能通过改善可管理性、性能和可用性,从而为各式应用程序带来了极大的好处。通常,分区可以使某些查询以及维护操作的性能大大提高。此外,分区还可以极大简化常见的管理任务。通过分区,数据库设计人员和管理员能够解决前沿应用程序带来的一些难题。分区是构建千兆字节数据系统或超高可用性系统的关键工具。
分区功能的基本知识
分区功能能够将表、索引或索引组织表进一步细分为段。这些数据库对象的段叫做分区。每个分区有自己的名称,还可以选择自己的存储特性。
从数据库管理员的角度来看,一个分区后的对象具有多个段,这些段既可进行集体管理,也可单独管理。这就使数据库管理员在管理分区后的对象时有相当大的灵活性。但是,从应用程序的角度来看,分区后的表与非分区表完全相同,使#S#D#命令访问分区后的表时,无需任何修改,表的分区是通过“分区键”来实现的,分区键指的是一些列,这些列决定了某一行所在的分区。Orac#数据#1#提供了六项技术用于对表进行分区:
#范围分区
每个分区都由一个分区键值范围指定(对于一个以日期列作为分区键的表,“2005年1月”分区包含分区键值为从“2005年1月1日”到“2005年1月31日”的行)。
范围分区表示例:
假设有一个企业的销售数据比较大,可以作一个范围分区表
创建四个表空间,为分区表所用,应该把分区放在不同的物理设备上,性能更好,可我的测试环境是同一个物理设备
1 select * from USER_TABLESPACES; 2 select * from DBA_TABLESPACE_GROUPS; 3 select * from dba_users; 4 select tablespace_name,file_id,file_name,autoextensible, 5 round(bytes/1024/1024/1024,3) "used(G)",round(maxbytes/1024/1024/1024,3) "size(G)" 6 from dba_data_files order by tablespace_name; 7 8 create tablespace lxl_test1 datafile '/dba/user_oracle/bspdev1/bspdev1/lxl_test1.dbf' size 50M; 9 CREATE TABLESPACE LXL_TEST2 DATAFILE '/dba/user_oracle/bspdev1/bspdev1/lxl_test2.dbf' size 50M; 10 CREATE TABLESPACE LXL_TEST3 DATAFILE '/dba/user_oracle/bspdev1/bspdev1/lxl_test3.dbf' size 50M; 11 CREATE TABLESPACE LXL_TEST4 DATAFILE '/dba/user_oracle/bspdev1/bspdev1/lxl_test4.dbf' size 50M; 12 --范围分区 13 create table tt_lxl_part_test1( 14 id number , 15 name varchar2(20), 16 total_cnt number, 17 price number, 18 create_tm date not null 19 )partition by range(create_tm) 20 (partition lxl_part1 values less than (to_date('2016-09-18','YYYY-MM-DD')) tablespace lxl_test1, 21 partition lxl_part2 values less than (to_date('2016-10-18','YYYY-MM-DD'))tablespace lxl_test2, 22 partition lxl_part3 values less than (to_date('2016-11-18','YYYY-MM-DD'))tablespace lxl_test3, 23 partition lxl_part4 values less than (to_date('2016-12-18','YYYY-MM-DD'))tablespace lxl_test4 24 ); 25 insert into tt_lxl_part_test1 values(1,'蔬菜','10','2.9',to_date('2016-09-10','YYYY-MM-DD')); 26 insert into tt_lxl_part_test1 values(2,'水果','13','7.9',to_date('2016-10-10','YYYY-MM-DD')); 27 insert into tt_lxl_part_test1 values(3,'零食','16','5.9',to_date('2016-11-10','YYYY-MM-DD')); 28 insert into tt_lxl_part_test1 values(4,'大米','17','11',to_date('2016-12-10','YYYY-MM-DD')); 29 30 select * from tt_lxl_part_test1 partition(lxl_part1); 31 select * from tt_lxl_part_test1 partition(lxl_part2); 32 select * from tt_lxl_part_test1 partition(lxl_part3); 33 select * from tt_lxl_part_test1 partition(lxl_part4); 34 --列表分区 35 create table lxl_part_test2( 36 id number(4), 37 name varchar2(30), 38 loca varchar2(30) 39 )partition by list(loca) 40 ( 41 partition p1 values('北京') tablespace lxl_test1, 42 partition p2 values('上海','天津','重庆') tablespace lxl_test2, 43 partition p3 values('广东','福建') tablespace lxl_test3, 44 partition p4 values(default) tablespace lxl_test4 45 ); 46 insert into lxl_part_test2 values(1,'李小龙','佛山'); 47 insert into lxl_part_test2 values(2,'顺丰','北京'); 48 insert into lxl_part_test2 values(3,'速运','上海'); 49 insert into lxl_part_test2 values(4,'系统集成','天津'); 50 insert into lxl_part_test2 values(5,'数据研发中心','重庆'); 51 insert into lxl_part_test2 values(6,'深圳','广东'); 52 insert into lxl_part_test2 values(7,'南山','福建'); 53 select * from lxl_part_test2 partition(p1); 54 select * from lxl_part_test2 partition(p2); 55 select * from lxl_part_test2 partition(p3); 56 select * from lxl_part_test2 partition(p4); 57 --散列分区 58 create table lxl_part_test3( 59 id number primary key, 60 class_id number(8) not null, 61 name varchar2(300), 62 finished_date date 63 ) 64 partition by hash(id) 65 ( 66 partition p01 tablespace lxl_test1, 67 partition p02 tablespace lxl_test2, 68 partition p03 tablespace lxl_test3 69 ); 70 insert into lxl_part_test3 values 71 (3,12, '上等的虎皮',to_date('2009-05-30','yyyy-mm-dd')); 72 insert into lxl_part_test3 values 73 (1,13, '虎皮',to_date('2009-05-30','yyyy-mm-dd')); 74 insert into lxl_part_test3 values 75 (200,15, '中等的虎皮',to_date('2009-05-30','yyyy-mm-dd')); 76 insert into lxl_part_test3 values 77 (230,19, '猫虎皮',to_date('2009-05-30','yyyy-mm-dd')); 78 79 select * from lxl_part_test3 partition(p01); 80 select * from lxl_part_test3 partition(p02); 81 select * from lxl_part_test3 partition(p03); 82 83 --组合分区 散列+范围 84 create table lxl_part_test4( 85 id number, 86 name varchar2(30), 87 finish_date date 88 )partition by range(finish_date) 89 subpartition by hash(id) 90 subpartitions 2 91 ( 92 partition p_group1 values less than(to_date('2016-09-18','YYYY-MM-DD')) TABLESPACE lxl_test1, 93 partition p_group2 values less than (to_date('2016-10-18','YYYY-MM-DD')) tablespace lxl_test2, 94 partition p_group3 values less than(maxvalue) tablespace lxl_test3 95 ); 96 insert into lxl_part_test4 values 97 (1,'所发生的',to_date('20161003','yyyymmdd')); 98 99 insert into lxl_part_test4 values 100 (2,'分区表测试',to_date('20161014','yyyymmdd')); 101 102 insert into lxl_part_test4 values 103 (3,'分区表规划',to_date('20161020','yyyymmdd')); 104 105 insert into lxl_part_test4 values 106 (4,'stream实施',to_date('20161018','yyyymmdd')); 107 108 insert into lxl_part_test4 values 109 (5,'oracle设计',to_date('20161103','yyyymmdd')); 110 111 insert into lxl_part_test4 values 112 (6,'数据库规划',to_date('20161103','yyyymmdd')); 113 114 select * from lxl_part_test4 partition(p_group3); 115 select * from lxl_part_test4 partition(p_group2); 116 select * from lxl_part_test4 partition(p_group1); 117 118 --组合分区 列表+范围 119 create table lxl_part_test5( 120 id NUMBER(6), 121 name VARCHAR2(20), 122 area VARCHAR2(30), 123 create_tm date 124 )partition by range(create_tm) 125 subpartition by list(area) 126 subpartition template( 127 subpartition east values('CHINA', 'JAPAN', 'INDIA', 'THAILAND'), 128 subpartition west values('AMERICA', 'GERMANY', 'ITALY', 'SWITZERLAND'), 129 subpartition other values(default)) 130 ( 131 partition p_group04 values less than(to_date('2016-09-18','YYYY-MM-DD')), 132 partition p_group05 values less than(to_date('2016-10-18','YYYY-MM-DD')), 133 partition p_group06 values less than(MAXVALUE) 134 ); 135 136 137 insert into lxl_part_test5 values (1,'阿斯顿发送到','china',to_date('2016-09-08','YYYY-MM-DD')); 138 139 insert into lxl_part_test5 values (2,'多福多寿','GERMANY',to_date('2016-09-17','YYYY-MM-DD')); 140 insert into lxl_part_test5 values (75,'oracle','JAPAN',to_date('2016-09-18','YYYY-MM-DD')); 141 insert into lxl_part_test5 values (34,'IBM','SWITZERLAND',to_date('2016-09-19','YYYY-MM-DD')); 142 insert into lxl_part_test5 values (43,'SUN','CHINA',to_date('2016-10-18','YYYY-MM-DD')); 143 insert into lxl_part_test5 values (876,'DELL','AMERICA',to_date('2017-09-18','YYYY-MM-DD')); 144 insert into lxl_part_test5 values (866,'SYSBASE','INDIA',to_date('2016-09-28','YYYY-MM-DD')); 145 146 select * from lxl_part_test5 partition(p_group04 );
#索引组织表可以按范围、列表或散列进行分区。
Oracle 数据库10g还提供了三种类型的分区索引:
#本地索引
本地索引是其分区方式与其所在基础表的分区方式一模一样的索引。本地索引的每个分区仅对应于其所在基础表的一个分区。
示例:
SQL> CREATE INDEX idx_dyx_part_test1 ON dyx_part_test1 (xiaos_date) LOCAL
2 (PARTITION idx_dyx_part_test1_01 TABLESPACE ts_xiaos2009q1,
3 PARTITION idx_dyx_part_test1_02 TABLESPACE ts_xiaos2009q2,
4 PARTITION idx_dyx_part_test1_03 TABLESPACE ts_xiaos2009q3,
5 PARTITION idx_dyx_part_test1_04 TABLESPACE ts_xiaos2009q4
6 ) TABLESPACE users;
Index created.
#全局分区索引
分区索引是使用不同于其所在表的分区键进行分区的索引,其所在表可以是分区表或非分区表。全局分区的索引可以使用
范围或散列分区进行分区。例如,某个表可以按月份进行范围分区,因此具有十二个分区,而该表上的索引则可以使用不同的分区键
进行范围分区,从而具有不同的分区数量。
分区索引就是在所有每个区上单独创建索引,它能自动维护,在drop或truncate某个分区时不影响该索引的其他分区索引的使用,也就是索
引不会失效,维护起来比较方便,但是在查询性能稍微有点影响
#全局非分区索引
全局非分区索引基本上和非分区表的索引一样。索引结构是不分区的。
Oracle 提供了一系列丰富的技术,可用于对表、索引和索引组织表进行分区,因此可以针对任何业务环境中的任何应用程序进行最佳的分区。
Oracle 还提供一套完整的SQL命令,用于管理分区表。其中包括添加新分区、删除分区、分拆分区以及合并分区的命令。
用分区功能提高可管理性
通过 Oracle 分区功能,可将表和索引分成更多、更小的可管理单元,从而使数据库管理员能以“化整为零,个个击破”的方式管理数据。
使用分区功能,维护操作可集中于表的特定部分。
例如,数据库管理员可以只对表的一部分做备份,而不必对整个表做备份。对整个数据库对象的维护操作,可以在每个分区的基础上进行,
从而将维护工作分解成更容易管理的小块。
利用分区功能提高可管理性的一个典型用法是支持数据仓库中的‘滚动视窗’加载进程。假设数据库管理员每周向表中加载新数据。可以对
该表进行范围分区,使每个分区包含一周的数据。这样加载进程只是简单地添加新的分区。添加一个分区的操作比修改整个表效率高很多,因
为 DBA 不需要修改任何其他分区。
用分区功能提高性能
由于限制了所检查或操作的数据数量,同时支持并行任务执行,Oracle 分区功能实现了性能上增益。这些特性包括:
#分区修整
分区修整是用分区功能提高性能的最简单最有价值的手段。分区修整常常能够将查询性能提高几个数量级。例如,假设某个应用程序包含一个存
储订单历史记录的 Orders 表,并且此表已按周分区。查询一周的订单只需访问该订单表的一个分区。如果该订单表包含两年的历史记录,这个
查询只需要访问一个分区而不是一百零四个。该查询的执行速度因为分区修整而有可能快一百倍。分区修整能与所有其他 Oracle 性能特性协作。
Oracle 能将分区修整功能与任何索引技术、联接技术或并行访问方法结合使用。
分区表的维护:
增加分区:
SQL> ALTER TABLE dyx_part_test1 ADD PARTITION xiaoss2009_q5
2 VALUES LESS THAN (TO_DATE('2010-06-01','YYYY-MM-DD'))
3 TABLESPACE users;
Table altered.
如果已有maxvalue分区,不能增加分区,可以采取分裂分区的办法增加分区!
删除分区:
SQL> ALTER TABLE dyx_part_test1 DROP partition xiaoss2009_q5;
Table altered.
截短分区:
SQL> alter table dyx_part_test1 truncate partition xiaoss2009_q4;
Table truncated.
合并分区:
SQL> alter table dyx_part_test1 merge partitions xiaoss2009_q3,xiaoss2009_q4 into partition xiaoss2009_q4;
Table altered.
SQL> alter index idx_dyx_part_test1 rebuild partition idx_dyx_part_test1_01 parallel 4;
Index altered.
分裂分区:
范围示例:
SQL> ALTER TABLE dyx_part_test1
2 SPLIT PARTITION xiaoss2009_q4
3 AT (TO_DATE('2009-10-01','YYYY-MM-DD'))
4 INTO (partition xiaoss2009_q3,partition xiaoss2009_q4);
Table altered.
列表示例:
SQL> select * from dyx_part_test2 partition(p2);
ID NAME LOCA
---------- ------------------------------ ------------------------------
3 广成子 天津
5 太已真人 上海
7 元始天尊 重庆
SQL> alter table dyx_part_test2 split partition p2 values ('天津','重庆') into (partition p5,partition p6);
Table altered.
SQL> select * from dyx_part_test2 partition(p2);
select * from dyx_part_test2 partition(p2)
*
ERROR at line 1:
ORA-02149: Specified partition does not exist
SQL> select * from dyx_part_test2 partition(p5);
ID NAME LOCA
---------- ------------------------------ ------------------------------
3 广成子 天津
7 元始天尊 重庆
SQL> select * from dyx_part_test2 partition(p6);
ID NAME LOCA
---------- ------------------------------ ------------------------------
5 太已真人 上海
注:分开的分区(上例中的p5和p6)不能是原分区表中已经有的不同于被分区的分区
交换分区:
交换分区(Exchange partition)提供了一种方式,让你在表与表或分区与分区之间迁移数据,注意不是将表转换成分区或非分区的形式,而仅只是迁移表中数据
(互相迁移),由于其号称是采用了更改数据字典的方式,因此效率最高(几乎不涉及io操作)。Exchange partition适用于所有分区格式,你可以将数据从分区表迁移
到非分区表,也可以从非分区表迁移至分区表,或者从hash partition到range partition诸如此类吧
SQL> create table dyx_part_test7 (id number,name varchar2(50))
2 partition by range(id)
3 (partition t_range_p1 values less than (10) tablespace ts_xiaos2009q1,
4 partition t_range_p2 values less than (20) tablespace ts_xiaos2009q2,
5 partition t_range_p3 values less than (30) tablespace ts_xiaos2009q3,
6 partition t_range_pmax values less than (maxvalue) tablespace ts_xiaos2009q4
7 );
Table created.
SQL> insert into dyx_part_test7 values (11,'a');
1 row created.
SQL> insert into dyx_part_test7 values (12,'b');
1 row created.
SQL> insert into dyx_part_test7 values (13,'c');
1 row created.
SQL> commit;
Commit complete.
SQL> create table dyx_part_test7_tmp (id number,name varchar2(50));
Table created.
SQL> alter table dyx_part_test7 exchange partition t_range_p2
2 with table dyx_part_test7_tmp;
Table altered.
SQL> select * from dyx_part_test7 partition(t_range_p2);
no rows selected
SQL> select * from dyx_part_test7_tmp;
ID NAME
---------- --------------------------------------------------
11 a
12 b
13 c
记录成功交换到未分区的表中
接着再执行一次交换
SQL> alter table dyx_part_test7 exchange partition t_range_p2
2 with table dyx_part_test7_tmp;
Table altered.
SQL> select * from dyx_part_test7_tmp;
no rows selected
SQL> select * from dyx_part_test7 partition(t_range_p2);
ID NAME
---------- --------------------------------------------------
11 a
12 b
13 c
从上面可以看出又交换回去了
SQL> insert into dyx_part_test7_tmp values (15,'d');
1 row created.
SQL> insert into dyx_part_test7_tmp values (16,'e');
1 row created.
SQL> insert into dyx_part_test7_tmp values (17,'d');
1 row created.
SQL>
SQL> commit;
Commit complete.
SQL> alter table dyx_part_test7 exchange partition t_range_p2
2 with table dyx_part_test7_tmp;
Table altered.
SQL>
SQL> select *from dyx_part_test7 partition(t_range_p2);
ID NAME
---------- --------------------------------------------------
15 d
16 e
17 d
SQL> select *from dyx_part_test7_tmp;
ID NAME
---------- --------------------------------------------------
11 a
12 b
13 c
从上面的测试可以看出,两个表或分区表是在交换数据!
注意:
参于交换的两表之间表结构必须一致,除非附加with validation子句;
如果是从非分区表向分区表做交换,非分区表中的数据必须符合分区表中指定分区的规则,除非附加without validation子句;
如果从分区表向分区表做交换,被交换的分区的数据必须符合分区规则,除非附加without validation子句;
Global索引或涉及到数据改动了的global索引分区会被置为unusable,除非附加update indexes子句。
提示:
一旦附加了without validation子句,则表示不再验证数据有效性,因此指定该子句时务必慎重。
访问指定分区:
SQL> select * from dyx_part_test2 partition(p1);
ID NAME LOCA
---------- ------------------------------ ------------------------------
2 云中子 北京
8 南级战神 北京
导出导入:
EXPORT指定分区:
[oracle@ora ~]$ exp dyx/dyx tables=dyx_part_test2:p1 file=dyx_part_test2_p1.dmp
Export: Release 10.2.0.1.0 - Production on Sat Apr 25 09:42:47 2009
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit Production
With the Partitioning, OLAP and Data Mining options
Export done in ZHS16GBK character set and AL16UTF16 NCHAR character set
About to export specified tables via Conventional Path ...
. . exporting table DYX_PART_TEST2
. . exporting partition P1 2 rows exported
EXP-00091: Exporting questionable statistics.
Export terminated successfully with warnings.
IMPORT指定分区:
[oracle@ora ~]$ imp dyx/dyx file=dyx_part_test2_p1.dmp TABLES=(dyx_part_test2:p1) IGNORE=y
Import: Release 10.2.0.1.0 - Production on Sat Apr 25 09:44:15 2009
Copyright (c) 1982, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit Production
With the Partitioning, OLAP and Data Mining options
Export file created by EXPORT:V10.02.01 via conventional path
import done in ZHS16GBK character set and AL16UTF16 NCHAR character set
. importing DYX's objects into DYX
. importing DYX's objects into DYX
. . importing partition "DYX_PART_TEST2":"P1" 2 rows imported
Import terminated successfully without warnings.
普通表变为分区表
将已存在数据的普通表转变为分区表,没有办法通过修改属性的方式直接转化为分区表,必须通过重建的方式进行转变,一般可以有三种方法:
方法一:利用原表重建分区表。
SQL> CREATE TABLE T (ID NUMBER PRIMARY KEY,TIME DATE);
Table created.
SQL> INSERT INTO T
2 SELECT ROWNUM, SYSDATE - ROWNUM FROM user_OBJECTS WHERE ROWNUM <= 5000;
57 rows created.
SQL> commit;
Commit complete.
SQL> CREATE TABLE T_NEW (ID, TIME) PARTITION BY RANGE (TIME)
2 (PARTITION P1 VALUES LESS THAN (TO_DATE('2009-01-01', 'YYYY-MM-DD')),
3 PARTITION P2 VALUES LESS THAN (TO_DATE('2009-04-01', 'YYYY-MM-DD')),
4 PARTITION P3 VALUES LESS THAN (TO_DATE('2009-10-01', 'YYYY-MM-DD')),
5 PARTITION P4 VALUES LESS THAN (MAXVALUE))
6 AS SELECT ID,TIME FROM T;
Table created.
更换表名
SQL> RENAME T TO T_OLD;
Table renamed.
SQL> SQL> RENAME T_NEW TO T;
Table renamed.
SQL> SELECT COUNT(*) FROM T PARTITION (P2);
COUNT(*)
----------
33
SQL> SELECT COUNT(*) FROM T PARTITION (P3);
COUNT(*)
----------
24
优点:方法简单易用,由于采用DDL语句,不会产生UNDO,且只产生少量REDO,效率相对较高,而且建表完成后数据已经在分布到各个分区中了。
不足:对于数据的一致性方面还需要额外的考虑。由于几乎没有办法通过手工锁定T表的方式保证一致性,在执行CREATE TABLE语句和RENAME T_NEW TO T语句直接的
修改可能会丢失,如果要保证一致性,需要在执行完语句后对数据进行检查,而这个代价是比较大的。另外在执行两个RENAME语句之间执行的对T的访问会失败。
适用于修改不频繁的表,在闲时进行操作,表的数据量不宜太大。
方法二:使用交换分区的方法。
因前面有闪换分区的示例,这里就不用重新示例了
优点:只是对数据字典中分区和表的定义进行了修改,没有数据的修改或复制,效率最高。如果对数据在分区中的分布没有进一步要求的话,实现比较简单。在执行
完RENAME操作后,可以检查T_OLD中是否存在数据,如果存在的话,直接将这些数据插入到T中,可以保证对T插入的操作不会丢失。
不足:仍然存在一致性问题,交换分区之后RENAME T_NEW TO T之前,查询、更新和删除会出现错误或访问不到数据。如果要求数据分布到多个分区中,则需要进行
分区的SPLIT操作,会增加操作的复杂度,效率也会降低。
适用于包含大数据量的表转到分区表中的一个分区的操作。应尽量在闲时进行操作。
方法三:Oracle9i以上版本,利用在线重定义功能
不作示例
优点:保证数据的一致性,在大部分时间内,表T都可以正常进行DML操作。只在切换的瞬间锁表,具有很高的可用性。这种方法具有很强的灵活性,对各种不同的需
要都能满足。而且,可以在切换前进行相应的授权并建立各种约束,可以做到切换完成后不再需要任何额外的管理操作。
相关视图:
显示当前用户可访问的所有分区表信息﹕ALL_PART_TABLES
显示当前用户所有分区表的信息﹕USER_PART_TABLES
显示表分区信息 显示数据库所有分区表的详细分区信息﹕DBA_TAB_PARTITIONS
显示当前用户可访问的所有分区表的详细分区信息﹕ALL_TAB_PARTITIONS
显示当前用户所有分区表的详细分区信息﹕USER_TAB_PARTITIONS
显示子分区信息 显示数据库所有组合分区表的子分区信息﹕DBA_TAB_SUBPARTITIONS
显示当前用户可访问的所有组合分区表的子分区信息﹕ALL_TAB_SUBPARTITIONS
显示当前用户所有组合分区表的子分区信息﹕USER_TAB_SUBPARTITIONS
显示分区列 显示数据库所有分区表的分区列信息﹕DBA_PART_KEY_COLUMNS
显示当前用户可访问的所有分区表的分区列信息﹕ALL_PART_KEY_COLUMNS
显示当前用户所有分区表的分区列信息﹕USER_PART_KEY_COLUMNS
显示子分区列 显示数据库所有分区表的子分区列信息﹕DBA_SUBPART_KEY_COLUMNS
显示当前用户可访问的所有分区表的子分区列信息﹕ALL_SUBPART_KEY_COLUMNS
显示当前用户所有分区表的子分区列信息﹕USER_SUBPART_KEY_COLUMNS
1.创建用户
create user DBAMON identified by "bspdev"
default tablespace BSP_DATA
temporary tablespace temp profile DEFAULT;
2.授权
grant connect to DBAMON;
grant create indextype to DBAMON;
grant create job to DBAMON;
grant create materialized view to DBAMON;
grant create procedure to DBAMON;
grant create public synonym to DBAMON;
grant create sequence to DBAMON;
grant create session to DBAMON;
grant create table to DBAMON;
grant create trigger to DBAMON;
grant create type to DBAMON;
grant create view to DBAMON;
grant unlimited tablespace to DBAMON;
alter user DBAMON quota unlimited on BSP_DATA;
grant connect,resource,dba to DBAMON
grant sys to DBAMON;
grant all on sys to DBAMON;
grant select on sys.dba_part_tables to DBAMON;
grant select on sys.dba_part_tables to bspdev;
grant select on sys.dba_tab_partitions to DBAMON;
grant select on sys.dba_tab_partitions to bspdev;
grant select on sys.dba_indexes to DBAMON;
grant select on sys.dba_indexes to bspdev;
grant select on sys.dba_ind_partitions to DBAMON;
grant select on sys.dba_ind_partitions to bspdev;
grant select on sys.DBA_TAB_COLUMNS to DBAMON;
grant select on sys.DBA_TAB_COLUMNS to bspdev;
grant select on sys.DBA_PART_KEY_COLUMNS to DBAMON;
grant select on sys.DBA_PART_KEY_COLUMNS to bspdev;
grant select on sys.v$instance to DBAMON;
grant select on v$instance to bspdev;
v$instance
select instance_name from sys.v_$instance;
alter user sys account unlock;
select * /*into v_count*/ from v$instance where version like '11%';
DECLARE
V_MSG VARCHAR(4000);
BEGIN
DBAMON.CONFIG_TAB_POLICY( v_MSG => V_MSG,
v_table_owner => 'BSPDEV',
v_table_name => 'TT_GEN_SPE_ROUTE_RECORD_BAK',
v_drop_time_units => 3,
v_policy => 4,
v_partition_type => 'MONTH' );
DBMS_OUTPUT.put_line(SUBSTR(V_MSG,1,1000));
COMMIT;
END;
/
select * from dba_part_tables t where t.table_name='TT_GEN_SPE_ROUTE_RECORD_BAK';
select * from tbl_part_info t where t.table_name='TT_GEN_SPE_ROUTE_RECORD_BAK';
create table DBAMON.TBL_PART_INFO
(
table_owner VARCHAR2(40),
table_name VARCHAR2(60),
min_partition VARCHAR2(60),
max_partition VARCHAR2(60),
min_date VARCHAR2(15),
max_date VARCHAR2(15),
min_value VARCHAR2(2000),
max_value VARCHAR2(2000),
partition_column_type VARCHAR2(20),
sample_time DATE,
existmax VARCHAR2(10),
format VARCHAR2(15),
partition_type VARCHAR2(10),
global_indx NUMBER(10),
part_column_name VARCHAR2(100),
autointerval VARCHAR2(100)
);
create table DBAMON.TBL_TAB_PART_CONFIG
(
id NUMBER(10) not null,
table_owner VARCHAR2(30) not null,
table_name VARCHAR2(30) not null,
partition_column_type VARCHAR2(26) not null,
partition_pre VARCHAR2(26) default 'P' not null,
partition_type VARCHAR2(30) not null,
drop_time_units NUMBER(10) not null,
add_time_units NUMBER(10) not null,
tablespace_name VARCHAR2(30),
index_tb_name VARCHAR2(30),
valid_flg NUMBER(1) not null,
config_type VARCHAR2(100),
format VARCHAR2(15),
shour NUMBER(2),
ehour NUMBER(2)
);
-- Add comments to the columns
comment on column DBAMON.TBL_TAB_PART_CONFIG.id
is 'ID , 没有业务含义';
comment on column DBAMON.TBL_TAB_PART_CONFIG.table_owner
is '需要维护的表属主';
comment on column DBAMON.TBL_TAB_PART_CONFIG.table_name
is '需要维护的表名';
comment on column DBAMON.TBL_TAB_PART_CONFIG.partition_column_type
is '分区列类型, 支持VARCHAR2和DATE,TIMESTAMP,CHAR,VARCHAR,类型';
comment on column DBAMON.TBL_TAB_PART_CONFIG.partition_pre
is '分区名前缀';
comment on column DBAMON.TBL_TAB_PART_CONFIG.partition_type
is '分区类型,月, 1 天,10天,5天,, WEEK';
comment on column DBAMON.TBL_TAB_PART_CONFIG.drop_time_units
is '保留分区个数';
comment on column DBAMON.TBL_TAB_PART_CONFIG.add_time_units
is '增加分区个数';
comment on column DBAMON.TBL_TAB_PART_CONFIG.tablespace_name
is '表空间';
comment on column DBAMON.TBL_TAB_PART_CONFIG.index_tb_name
is '所音表空间';
comment on column DBAMON.TBL_TAB_PART_CONFIG.valid_flg
is '可用标记 1 加删 2不加不删,3分区只加不删,4 只删不加';
comment on column DBAMON.TBL_TAB_PART_CONFIG.config_type
is 'test,and run';
comment on column DBAMON.TBL_TAB_PART_CONFIG.format
is '分区类型为字符的格式YYYYMM或者YYYY-MM';
comment on column DBAMON.TBL_TAB_PART_CONFIG.shour
is 'start hour 0-23';
comment on column DBAMON.TBL_TAB_PART_CONFIG.ehour
is 'end hour 1-24';
-- Create/Recreate primary, unique and foreign key constraints
alter table DBAMON.TBL_TAB_PART_CONFIG
add constraint PK_TAB_PART_ID primary key (ID)
using index;
alter table DBAMON.TBL_TAB_PART_CONFIG
add constraint C_CHECK_CONFIG
check (PARTITION_TYPE IN ('MONTH','DAY','TEN','WEEK','FIVE'));
alter table DBAMON.TBL_TAB_PART_CONFIG
add constraint C_COLUMN_TYPE
check (PARTITION_COLUMN_TYPE IN ('VARCHAR2','DATE'));
alter table DBAMON.TBL_TAB_PART_CONFIG
add constraint C_EHOUR
check (EHOUR IN (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24) AND EHOUR>SHOUR);
alter table DBAMON.TBL_TAB_PART_CONFIG
add constraint C_SHOUR
check (SHOUR IN (0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23));
-- Create table
create table DBAMON.TBL_PART_MANAGE_SQL
(
gid NUMBER(10),
table_owner VARCHAR2(30),
table_name VARCHAR2(50),
partition_name VARCHAR2(100),
max_date VARCHAR2(20),
sql_text VARCHAR2(4000),
create_time DATE,
order_id NUMBER(10) not null,
resultmsg VARCHAR2(100)
);
-- Create/Recreate indexes
create index DBAMON.IDX_SQLCREATETIME on DBAMON.TBL_PART_MANAGE_SQL (CREATE_TIME);
-- Create/Recreate primary, unique and foreign key constraints
alter table DBAMON.TBL_PART_MANAGE_SQL
add primary key (ORDER_ID)
using index ;
-- Create table
create table DBAMON.TBL_PART_ERR
(
proc_name VARCHAR2(100),
errmsg VARCHAR2(100),
sample_time DATE
);
-- Create table
create table DBAMON.TBL_CONFIG_LOG
(
config_time DATE,
username VARCHAR2(50),
oseruser VARCHAR2(50),
proxy_user VARCHAR2(50),
ip_addr VARCHAR2(100),
machine VARCHAR2(50),
table_owner VARCHAR2(50),
table_name VARCHAR2(50),
drop_time_units NUMBER(3),
policy NUMBER(3),
v_start_time NUMBER(3),
v_end_time NUMBER(3),
v_partition_type VARCHAR2(30),
v_tab_tbs VARCHAR2(50),
v_inx_tbs VARCHAR2(50),
config_result VARCHAR2(2000)
);
create sequence DBAMON.SEQ_TM_PART_MAINTEN
minvalue 1
maxvalue 100000
start with 1
increment by 1
cache 5
cycle;
create sequence DBAMON.SEQ_SQL_ORDER
minvalue 1
maxvalue 10000000
start with 1
increment by 1
cache 20;
CREATE OR REPLACE PACKAGE BODY DBAMON.PKG_MAINTEN_PART as
--增加按月分区的SQL
PROCEDURE STP_ADD_MON_DT AS
v_currmax_date date;
v_partdate varchar2(20);
v_high_value varchar2(4000);
v_partname varchar2(30);
v_part_date date;
v_tablespace_name varchar2(80);
v_partition_cnt number(10);
v_tempname varchar2(50);
v_id number;
v_isdefault varchar2(20);
v_sql varchar2(1000);
v_errmsg varchar2(1000);
v_maxpart varchar2(100);
v_tempower varchar2(100);
v_hour number(2);
---v1 tbl_part_manage_sql 修改为日志表。 记录执行时的日志。增加执行时的判断,记录报错信息。
---v2 考虑split分区的情况,
---v3 分区自动维护加分区会有问题。不再判断, 允许报错。
---v4 分区指定表空间对于子分区SQL 可能会报错。修改未指定表空间的分区SQL不指定表空间。
--- author: bobo at 2014-09-10
---v5 varchange
BEGIN
/*delete tbl_part_manage_sql;*/
commit;
v_hour := to_number(to_char(sysdate, 'HH24'));
select SEQ_TM_PART_MAINTEN.nextval into v_id from dual;
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'MONTH'
and p.partition_column_type = 'DATE'
and p.valid_flg in (1, 3)
and v_hour >= p.shour
and v_hour < p.ehour) loop
v_tempname := rm.table_name;
v_maxpart := null;
v_tempower := rm.table_owner;
--- 获取分区最大值
v_currmax_date := null;
v_isdefault := 'FALSE';
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 4000);
--- 判断是否存在MAXVALUE, 如果存在则只能使用SPLIT分区,记录DEFAULT 分区名字
if v_high_value = 'MAXVALUE' then
v_isdefault := 'TRUE';
v_maxpart := cur_part.partition_name;
else
execute immediate 'select ' || v_high_value || ' from dual'
into v_part_date;
if v_currmax_date <= v_part_date or v_currmax_date is null then
v_currmax_date := v_part_date;
end if;
end if;
end loop;
---如果配置表里表空间为空,不指定表空间参数
if rm.tablespace_name is null then
v_tablespace_name := '';
else
v_tablespace_name := ' tablespace ' || rm.tablespace_name;
end if;
---生成加分区SQL并执行。
while (add_months(v_currmax_date, -rm.add_time_units) <=
trunc(sysdate, 'MM')) loop
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM');
v_partdate := to_char(trunc(add_months(v_currmax_date, 1)),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := add_months(v_currmax_date, 1);
select count(1)
into v_partition_cnt
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
and partition_name = rm.partition_pre || v_partname;
if (v_partition_cnt = 0) then
if v_isdefault = 'FALSE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' add partition ' || rm.partition_pre ||
v_partname || ' values less than (to_date(''' ||
v_partdate || ''',''YYYY-MM-DD HH24:MI:SS''))' ||
v_tablespace_name;
elsif v_isdefault = 'TRUE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' split partition ' || v_maxpart ||
' at (to_date(''' || v_partdate ||
''', ''YYYY-MM-DD HH24:MI:SS'')) into (partition ' ||
rm.partition_pre || v_partname || ',partition ' ||
v_maxpart || ')';
end if;
---执行加分区的SQL
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
--如果配置了索引表空间索引,索引分区需rebuild到指定的索引表空间
if (rm.index_tb_name is not null) then
for cur_part_ind in (select distinct a.index_owner, a.index_name
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and a.index_owner = rm.table_owner) loop
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
rm.partition_pre || v_partname || ' tablespace ' ||
rm.index_tb_name;
--- 执行SQL 重建索引
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end if;
end if;
end loop;
--重建不可用的局部索引
for cur_part_ind in (select a.index_owner,
a.index_name,
a.partition_name,
a.tablespace_name,
a.status
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and b.table_owner = rm.table_owner
and a.status = 'UNUSABLE') loop
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
cur_part_ind.partition_name || ' tablespace ' ||
cur_part_ind.tablespace_name || ' parallel 4';
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
cur_part_ind.index_owner,
cur_part_ind.index_name,
cur_part_ind.partition_name,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end loop;
commit;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempower,
v_tempower,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
END STP_ADD_MON_DT;
PROCEDURE STP_ADD_DAY_DT AS
v_currmax_date date;
v_partdate varchar2(20);
v_high_value varchar2(4000);
v_partname varchar2(30);
v_part_date date;
v_tablespace_name varchar2(80);
v_partition_cnt number(10);
v_tempname varchar2(50);
v_id number;
v_isdefault varchar2(20);
v_sql varchar2(1000);
v_errmsg varchar2(1000);
v_maxpart varchar2(100);
v_tempower varchar2(100);
v_hour number(2);
---v1 tbl_part_manage_sql 修改为日志表。 记录执行时的日志。增加执行时的判断,记录报错信息。
---v2 考虑split分区的情况,
---v3 分区自动维护加分区会有问题。不再判断, 允许报错。
BEGIN
/*delete tbl_part_manage_sql;*/
v_hour := to_number(to_char(sysdate, 'HH24'));
select SEQ_TM_PART_MAINTEN.nextval into v_id from dual;
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'DAY'
and p.partition_column_type = 'DATE'
and p.valid_flg IN (1, 3)
and v_hour >= p.shour
and v_hour < p.ehour) loop
v_tempname := rm.table_name;
v_currmax_date := null;
v_tempower := rm.table_owner;
--- 获取分区最大值
v_isdefault := 'FALSE';
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 4000);
--- 判断是否存在MAXVALUE, 如果存在则只能使用SPLIT分区,记录DEFAULT 分区名字
if v_high_value = 'MAXVALUE' then
v_isdefault := 'TRUE';
v_maxpart := cur_part.partition_name;
else
---获取分区的MAX_VALUE.转化成DATE类型
execute immediate 'select ' || v_high_value || ' from dual'
into v_part_date;
----判断是否分区最大值
if v_currmax_date <= v_part_date or v_currmax_date is null then
v_currmax_date := v_part_date;
end if;
end if;
end loop;
---获取表空间名字
if rm.tablespace_name is null then
v_tablespace_name := '';
else
v_tablespace_name := ' tablespace ' || rm.tablespace_name;
end if;
---生成加分区SQL并执行。
while (v_currmax_date - rm.add_time_units <= trunc(sysdate)) loop
v_partname := to_char(trunc(v_currmax_date), 'YYYYMMDD');
v_partdate := to_char(v_currmax_date + 1,
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := v_currmax_date + 1;
select count(1)
into v_partition_cnt
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
and partition_name = rm.partition_pre || v_partname;
if (v_partition_cnt <> 0) then
v_partname := v_partname || 's';
end if;
if v_isdefault = 'FALSE' then
v_sql := 'alter table ' || rm.table_owner || '.' || rm.table_name ||
' add partition ' || rm.partition_pre || v_partname ||
' values less than (to_date(''' || v_partdate ||
''',''YYYY-MM-DD HH24:MI:SS''))' || v_tablespace_name;
elsif v_isdefault = 'TRUE' then
v_sql := 'alter table ' || rm.table_owner || '.' || rm.table_name ||
' split partition ' || v_maxpart || ' at (to_date(''' ||
v_partdate ||
''', ''YYYY-MM-DD HH24:MI:SS'')) into (partition ' ||
rm.partition_pre || v_partname || ',partition ' ||
v_maxpart || ')';
end if;
---执行加分区的SQL
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
--如果配置了索引表空间索引,索引分区需rebuild到指定的索引表空间
if (rm.index_tb_name is not null) then
for cur_part_ind in (select distinct a.index_owner, a.index_name
/* a.index_owner,
a.index_name,
a.partition_name,
a.tablespace_name,
a.status*/
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and a.index_owner = rm.table_owner
/*and a.partition_name =
rm.partition_pre || v_partname*/
) loop
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
rm.partition_pre || v_partname || ' tablespace ' ||
rm.index_tb_name;
--- 执行SQL 重建索引
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end if;
end loop;
--重建不可用的局部索引
for cur_part_ind in (select a.index_owner,
a.index_name,
a.partition_name,
a.tablespace_name,
a.status
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and b.table_owner = rm.table_owner
and a.status = 'UNUSABLE') loop
begin
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
cur_part_ind.partition_name || ' tablespace ' ||
cur_part_ind.tablespace_name;
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
cur_part_ind.index_owner,
cur_part_ind.index_name,
cur_part_ind.partition_name,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end loop;
commit;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
---纪录异常日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempower,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
END STP_ADD_DAY_DT;
PROCEDURE STP_ADD_DAY_VAR AS
v_currmax_date date;
v_partdate varchar2(20);
v_high_value varchar2(4000);
v_partname varchar2(30);
v_part_date date;
v_tablespace_name varchar2(80);
v_partition_cnt number(10);
v_tempname varchar2(50);
v_id number;
v_isdefault varchar2(20);
v_sql varchar2(1000);
v_errmsg varchar2(1000);
v_maxpart varchar2(100);
v_tempower varchar2(100);
v_hour number(2);
v_current_maxval varchar2(3000);
---v1 tbl_part_manage_sql 修改为日志表。 记录执行时的日志。增加执行时的判断,记录报错信息。
---v2 考虑split分区的情况,
---v3 分区自动维护加分区会有问题。不再判断, 允许报错。
BEGIN
/*delete tbl_part_manage_sql;*/
v_hour := to_number(to_char(sysdate, 'HH24'));
select SEQ_TM_PART_MAINTEN.nextval into v_id from dual;
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'DAY'
and p.partition_column_type = 'VARCHAR2'
and p.valid_flg IN (1, 3)
and v_hour >= p.shour
and v_hour < p.ehour) loop
v_tempname := rm.table_name;
v_tempower := rm.table_owner;
--- 获取分区最大值
v_isdefault := 'FALSE';
v_current_maxval := null;
v_currmax_date := null;
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 4000);
--- 判断是否存在MAXVALUE, 如果存在则只能使用SPLIT分区,记录DEFAULT 分区名字
if v_high_value = 'MAXVALUE' then
v_isdefault := 'TRUE';
v_maxpart := cur_part.partition_name;
elsif v_current_maxval < v_high_value or v_current_maxval is null then
v_current_maxval := v_high_value;
end if;
end loop;
if rm.format = 'YYYY-MM-DD' then
v_part_date := to_date(substr(v_current_maxval, 2, 10),
'YYYY-MM-DD');
elsif rm.format = 'YYYYMMDD' then
v_part_date := to_date(substr(v_current_maxval, 2, 8), 'YYYYMMDD');
end if;
v_currmax_date := v_part_date;
---如果配置表里表空间为空,找出该表目前所用表空间
if rm.tablespace_name is null then
/* select tablespace_name
into v_tablespace_name
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
and rownum = 1;*/
v_tablespace_name := '';
else
v_tablespace_name := ' tablespace ' || rm.tablespace_name;
end if;
---生成加分区SQL并执行。
while (v_currmax_date - rm.add_time_units <= trunc(sysdate)) loop
v_partname := to_char(trunc(v_currmax_date), 'YYYYMMDD');
if rm.format = 'YYYY-MM-DD' then
v_partdate := to_char(trunc(v_currmax_date) + 1, 'YYYY-MM-DD');
elsif rm.format = 'YYYYMMDD' then
v_partdate := to_char(trunc(v_currmax_date) + 1, 'YYYYMMDD');
end if;
v_currmax_date := v_currmax_date + 1;
select count(1)
into v_partition_cnt
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
and partition_name = rm.partition_pre || v_partname;
if (v_partition_cnt = 0) then
if v_isdefault = 'FALSE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' add partition ' || rm.partition_pre ||
v_partname || ' values less than (''' || v_partdate ||
''') ' || v_tablespace_name;
elsif v_isdefault = 'TRUE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' split partition ' || v_maxpart ||
' at (''' || v_partdate || ''' into (partition ' ||
rm.partition_pre || v_partname || ',partition ' ||
v_maxpart || ')';
end if;
---执行加分区的SQL
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
--如果配置了索引表空间索引,索引分区需rebuild到指定的索引表空间
if (rm.index_tb_name is not null) then
for cur_part_ind in (select distinct a.index_owner, a.index_name
/* a.index_owner,
a.index_name,
a.partition_name,
a.tablespace_name,
a.status*/
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and a.index_owner = rm.table_owner
/*and a.partition_name =
rm.partition_pre || v_partname*/
) loop
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
rm.partition_pre || v_partname || ' tablespace ' ||
rm.index_tb_name;
--- 执行SQL 重建索引
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end if;
end if;
end loop;
--重建不可用的局部索引
for cur_part_ind in (select a.index_owner,
a.index_name,
a.partition_name,
a.tablespace_name,
a.status
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and b.table_owner = rm.table_owner
and a.status = 'UNUSABLE') loop
begin
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
cur_part_ind.partition_name || ' tablespace ' ||
cur_part_ind.tablespace_name;
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
cur_part_ind.index_owner,
cur_part_ind.index_name,
cur_part_ind.partition_name,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end loop;
commit;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
---纪录异常日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempower,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
END STP_ADD_DAY_VAR;
PROCEDURE STP_ADD_MON_VAR AS
v_currmax_date date;
v_partdate varchar2(20);
v_high_value varchar2(4000);
v_partname varchar2(30);
v_part_date date;
v_tablespace_name varchar2(80);
v_partition_cnt number(10);
v_id number;
v_isdefault varchar2(20);
v_sql varchar2(1000);
v_errmsg varchar2(1000);
v_maxpart varchar2(100);
v_tempowner varchar2(100);
v_tempname varchar2(50);
v_hour number(2);
v_current_maxval varchar2(3000);
---V1:var类型的分区MAXVALUE 字段有两种,一种是YYYY-MM,另外一种是YYYYMM. 需要分别处理。
---
BEGIN
---删除SQL,测试用
/*delete tbl_part_manage_sql;*/
v_hour := to_number(to_char(sysdate, 'HH24'));
select SEQ_TM_PART_MAINTEN.nextval into v_id from dual; --获取本次处理的ID
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'MONTH'
and p.partition_column_type = 'VARCHAR2'
and p.valid_flg in (1, 3)
and v_hour >= p.shour
and v_hour < p.ehour) loop
v_tempowner := rm.table_owner;
v_tempname := rm.table_name;
v_isdefault := 'FALSE';
--v_currmax_date := null;
v_current_maxval := null;
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
-- 获取当前分区的最大值, 转化为DATE类型
v_high_value := substr(cur_part.high_value, 1, 2000);
--- 判断是否存在MAXVALUE, 如果存在则只能使用SPLIT分区,记录DEFAULT 分区名字
if v_high_value = 'MAXVALUE' then
v_isdefault := 'TRUE';
v_maxpart := cur_part.partition_name;
elsif v_current_maxval < v_high_value or v_current_maxval is null then
v_current_maxval := v_high_value;
end if;
end loop;
if rm.format = 'YYYY-MM' then
v_part_date := to_date(substr(v_current_maxval, 2, 7), 'YYYY-MM');
elsif rm.format = 'YYYYMM' then
v_part_date := to_date(substr(v_current_maxval, 2, 6), 'YYYYMM');
end if;
v_currmax_date := v_part_date;
--如果配置表里表空间为空,找出该表目前所用表空间
if rm.tablespace_name is null then
select tablespace_name
into v_tablespace_name
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
and rownum = 1;
else
v_tablespace_name := rm.tablespace_name;
end if;
--增加分区
while (add_months(v_currmax_date, -rm.add_time_units) <=
trunc(sysdate, 'MM')) loop
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM');
if rm.format = 'YYYY-MM' THEN
v_partdate := to_char(trunc(add_months(v_currmax_date, 1)),
'YYYY-MM');
elsif rm.format = 'YYYYMM' THEN
v_partdate := to_char(trunc(add_months(v_currmax_date, 1)),
'YYYYMM');
end if;
v_currmax_date := add_months(v_currmax_date, 1);
select count(1)
into v_partition_cnt
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
and partition_name = rm.partition_pre || v_partname;
if (v_partition_cnt = 0) then
-- ADD 分区
if v_isdefault = 'FALSE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' add partition ' || rm.partition_pre ||
v_partname || ' values less than (''' || v_partdate ||
''') tablespace ' || v_tablespace_name;
elsif v_isdefault = 'TRUE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' split partition ' || v_maxpart ||
' at ''' || v_partdate || ''' into (partition ' ||
rm.partition_pre || v_partname || ',partition ' ||
v_maxpart || ')';
end if;
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
--如果配置了索引表空间索引,索引分区需rebuild到指定的索引表空间
if (rm.index_tb_name is not null) then
for cur_part_ind in (select distinct a.index_owner, a.index_name
/* a.index_owner,
a.index_name,
a.partition_name,
a.tablespace_name,
a.status*/
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and a.index_owner = rm.table_owner
/*and a.partition_name =
rm.partition_pre || v_partname*/
) loop
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
rm.partition_pre || v_partname || ' tablespace ' ||
rm.index_tb_name;
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end if;
end if;
end loop;
--重建不可用的局部索引
for cur_part_ind in (select a.index_owner,
a.index_name,
a.partition_name,
a.tablespace_name,
a.status
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and b.table_owner = rm.table_owner
and a.status = 'UNUSABLE') loop
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
cur_part_ind.partition_name || ' tablespace ' ||
cur_part_ind.tablespace_name;
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempowner,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end loop;
commit;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
---纪录异常日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempowner,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
END STP_ADD_MON_VAR;
PROCEDURE STP_DEL_MON AS
v_currmax_date date;
v_high_value varchar2(4000);
v_part_date date;
v_drop_date date;
v_partname varchar2(50);
v_partdate varchar2(10);
v_id number;
v_sql varchar2(1000);
v_errmsg varchar2(1000);
v_tempowner varchar2(100);
v_tempname varchar2(50);
v_hour number(2);
v_dropval varchar2(50);
v_count NUMBER;
BEGIN
/*delete tbl_part_manage_sql;*/
v_hour := to_number(to_char(sysdate, 'HH24'));
select SEQ_TM_PART_MAINTEN.nextval into v_id from dual;
--处理DATE类型的分区表
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type IN ('MONTH')
and p.partition_column_type = 'DATE'
and p.valid_flg in (1, 4)
and v_hour >= p.shour
and v_hour < p.ehour) loop
v_tempname := rm.table_name;
v_tempowner := rm.table_owner;
v_currmax_date := null;
--获取删除的最大DATE
v_drop_date := add_months(trunc(sysdate, 'MM'), -rm.drop_time_units);
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 4000);
if v_high_value = 'MAXVALUE' then
null;
else
execute immediate 'select ' || v_high_value || ' from dual'
into v_part_date;
if v_drop_date >= v_part_date then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' drop partition ' ||
cur_part.partition_name;
v_partname := cur_part.partition_name;
v_partdate := to_char(v_part_date, 'YYYY-MM-DD');
---if there is any global index.
select count(*)
into v_count
from dba_indexes t
where t.table_owner = RM.TABLE_OWNER
AND T.table_name = rm.table_name
and PARTITIONED = 'NO';
begin
if rm.config_Type = 'TEST' and v_count = 0 then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' and v_count = 0 then
v_errmsg := 'OK';
execute immediate v_sql;
else
v_errmsg := 'GLOBAL_INDEXES';
v_sql:=v_sql||' UPDATE GLOBAL INDEXES';
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempowner,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end if;
end if;
end loop;
end loop;
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'MONTH'
and p.partition_column_type = 'VARCHAR2'
and p.valid_flg in (1, 4)) loop
v_tempname := rm.table_name;
v_tempowner := rm.table_owner;
v_drop_date := add_months(trunc(sysdate, 'MM'), -rm.drop_time_units);
if rm.format = 'YYYY-MM' then
v_dropval := ''''||TO_CHAR(v_drop_date, 'YYYY-MM')||'''';
elsif rm.format = 'YYYYMM' then
v_dropval := ''''||TO_CHAR(v_drop_date, 'YYYYMM')||'''';
elsif rm.format = 'YYYYMMDD' then
v_dropval := ''''||TO_CHAR(v_drop_date, 'YYYYMMDD')||'''';
elsif rm.format = 'YYYY-MM-DD' then
v_dropval := ''''||TO_CHAR(v_drop_date, 'YYYY-MM-DD')||'''';
end if;
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 2000);
if v_high_value = 'MAXVALUE' then
null;
else
if v_dropval >= v_high_value then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' drop partition ' ||
cur_part.partition_name;
v_partname := cur_part.partition_name;
v_partdate := v_high_value;
select count(*)
into v_count
from dba_indexes t
where t.table_owner = RM.TABLE_OWNER
AND T.table_name = rm.table_name
and PARTITIONED = 'NO';
begin
if rm.config_Type = 'TEST' and v_count = 0 then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' and v_count = 0 then
v_errmsg := 'OK';
execute immediate v_sql;
else
v_errmsg := 'GLOBAL_INDEXES';
v_sql:=v_sql||' UPDATE GLOBAL INDEXES';
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempowner,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end if;
end if;
end loop;
for cur_part_ind in (select a.index_owner,
a.index_name,
a.partition_name,
a.tablespace_name,
a.status
from dba_ind_partitions a, dba_indexes b
where a.index_name = b.index_name
and b.table_name = rm.table_name
and b.table_owner = rm.table_owner
and a.status = 'UNUSABLE') loop
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
cur_part_ind.partition_name || ' tablespace ' ||
cur_part_ind.tablespace_name;
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
end loop;
end loop;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
---纪录异常日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempowner,
v_tempname,
'ALL',
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
END STP_DEL_MON;
PROCEDURE STP_DEL_DAY AS
v_currmax_date date;
v_high_value varchar2(4000);
v_part_date date;
v_drop_date date;
v_id number;
v_sql varchar2(1000);
v_errmsg varchar2(1000);
v_tempowner varchar2(100);
v_tempname varchar2(50);
v_partname varchar2(50);
v_partdate varchar2(20);
v_hour number(2);
v_dropval varchar2(50);
v_count NUMBER;
BEGIN
/*delete tbl_part_manage_sql;*/
v_hour := to_number(to_char(sysdate, 'HH24'));
select SEQ_TM_PART_MAINTEN.nextval into v_id from dual;
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'DAY'
and p.partition_column_type = 'DATE'
and p.valid_flg in (1, 4)
and v_hour >= p.shour
and v_hour < p.ehour) loop
v_tempname := rm.table_name;
v_tempowner := rm.table_owner;
v_currmax_date := null;
v_drop_date := trunc(sysdate, 'DD') - rm.drop_time_units;
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 4000);
if v_high_value = 'MAXVALUE' then
null;
else
execute immediate 'select ' || v_high_value || ' from dual'
into v_part_date;
if v_drop_date >= v_part_date then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' drop partition ' ||
cur_part.partition_name;
v_partname := cur_part.partition_name;
v_partdate := to_char(v_part_date, 'YYYY-MM-DD');
select count(*)
into v_count
from dba_indexes t
where t.table_owner = RM.TABLE_OWNER
AND T.table_name = rm.table_name
and PARTITIONED = 'NO';
begin
if rm.config_Type = 'TEST' and v_count = 0 then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' and v_count = 0 then
v_errmsg := 'OK';
execute immediate v_sql;
else
v_errmsg := 'GLOBAL_INDEXES';
v_sql:=v_sql||' UPDATE GLOBAL INDEXES';
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempowner,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end if;
end if;
end loop;
end loop;
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'DAY'
and p.partition_column_type = 'VARCHAR2'
and p.valid_flg in (1, 4)) loop
v_tempname := rm.table_name;
v_currmax_date := null;
v_drop_date := trunc(sysdate) - rm.drop_time_units;
if rm.format = 'YYYY-MM-DD' THEN
v_dropval := ''''||to_char(v_drop_date, 'YYYY-MM-DD')||'''';
elsif rm.format = 'YYYYMMDD' THEN
v_dropval := ''''||to_char(v_drop_date, 'YYYYMMDD')||'''';
end if;
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 2000);
if v_high_value = 'MAXVALUE' then
null;
else
if v_dropval >= v_high_value then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' drop partition ' ||
cur_part.partition_name;
v_partname := cur_part.partition_name;
v_partdate := v_high_value;
select count(*)
into v_count
from dba_indexes t
where t.table_owner = RM.TABLE_OWNER
AND T.table_name = rm.table_name
and PARTITIONED = 'NO';
begin
if rm.config_Type = 'TEST' and v_count = 0 then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' and v_count = 0 then
v_errmsg := 'OK';
execute immediate v_sql;
else
v_errmsg := 'GLOBAL_INDEXES';
v_sql:=v_sql||' UPDATE GLOBAL INDEXES';
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempowner,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end if;
end if;
end loop;
end loop;
commit;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempowner,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
END STP_DEL_DAY;
PROCEDURE STP_ADD_WEEK_DT AS
v_currmax_date date;
v_partdate varchar2(20);
v_high_value varchar2(4000);
v_partname varchar2(30);
v_part_date date;
v_tablespace_name varchar2(80);
v_partition_cnt number(10);
v_tempname varchar2(50);
v_id number;
v_isdefault varchar2(20);
v_sql varchar2(1000);
v_errmsg varchar2(1000);
v_maxpart varchar2(100);
v_tempower varchar2(100);
v_hour number(2);
---v1 tbl_part_manage_sql 修改为日志表。 记录执行时的日志。增加执行时的判断,记录报错信息。
---v2 考虑split分区的情况,
---v3 分区自动维护加分区会有问题。不再判断, 允许报错。
---v4 分区指定表空间对于子分区SQL 可能会报错。修改未指定表空间的分区SQL不指定表空间。
BEGIN
/*delete tbl_part_manage_sql;*/
v_hour := to_number(to_char(sysdate, 'HH24'));
select SEQ_TM_PART_MAINTEN.nextval into v_id from dual;
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'WEEK'
and p.partition_column_type = 'DATE'
and p.valid_flg in (1, 3)
and v_hour >= p.shour
and v_hour < p.ehour) loop
v_tempname := rm.table_name;
v_maxpart := null;
v_tempower := rm.table_owner;
--- 获取分区最大值
v_currmax_date := null;
v_isdefault := 'FALSE';
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 4000);
--- 判断是否存在MAXVALUE, 如果存在则只能使用SPLIT分区,记录DEFAULT 分区名字
if v_high_value = 'MAXVALUE' then
v_isdefault := 'TRUE';
v_maxpart := cur_part.partition_name;
else
execute immediate 'select ' || v_high_value || ' from dual'
into v_part_date;
if v_currmax_date <= v_part_date or v_currmax_date is null then
v_currmax_date := v_part_date;
end if;
end if;
end loop;
---如果配置表里表空间为空,不指定表空间参数
if rm.tablespace_name is null then
v_tablespace_name := '';
else
v_tablespace_name := ' tablespace ' || rm.tablespace_name;
end if;
---生成加分区SQL并执行。
while (v_currmax_date - rm.add_time_units * 7 <= SYSDATE) loop
v_partname := to_char(trunc(v_currmax_date), 'YYYYMMDD');
v_partdate := TO_CHAR(trunc(v_currmax_date + 7),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := v_currmax_date + 7;
select count(1)
into v_partition_cnt
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
and partition_name = rm.partition_pre || v_partname;
if (v_partition_cnt = 0) then
if v_isdefault = 'FALSE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' add partition ' || rm.partition_pre ||
v_partname || ' values less than (to_date(''' ||
v_partdate || ''',''YYYY-MM-DD HH24:MI:SS''))' ||
v_tablespace_name;
elsif v_isdefault = 'TRUE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' split partition ' || v_maxpart ||
' at (to_date(''' || v_partdate ||
''', ''YYYY-MM-DD HH24:MI:SS'')) into (partition ' ||
rm.partition_pre || v_partname || ',partition ' ||
v_maxpart || ')';
end if;
---执行加分区的SQL
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
--如果配置了索引表空间索引,索引分区需rebuild到指定的索引表空间
if (rm.index_tb_name is not null) then
for cur_part_ind in (select distinct a.index_owner, a.index_name
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and a.index_owner = rm.table_owner) loop
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
rm.partition_pre || v_partname || ' tablespace ' ||
rm.index_tb_name;
--- 执行SQL 重建索引
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end if;
end if;
end loop;
--重建不可用的局部索引
for cur_part_ind in (select a.index_owner,
a.index_name,
a.partition_name,
a.tablespace_name,
a.status
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and b.table_owner = rm.table_owner
and a.status = 'UNUSABLE') loop
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
cur_part_ind.partition_name || ' tablespace ' ||
cur_part_ind.tablespace_name;
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
cur_part_ind.index_owner,
cur_part_ind.index_name,
cur_part_ind.partition_name,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end loop;
commit;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempower,
v_tempower,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
END STP_ADD_WEEK_DT;
PROCEDURE STP_ADD_WEEK_VAR AS
v_currmax_date date;
v_partdate varchar2(20);
v_high_value varchar2(4000);
v_partname varchar2(30);
v_part_date date;
v_tablespace_name varchar2(80);
v_partition_cnt number(10);
v_tempname varchar2(50);
v_id number;
v_isdefault varchar2(20);
v_sql varchar2(1000);
v_errmsg varchar2(1000);
v_maxpart varchar2(100);
v_tempower varchar2(100);
v_hour number(2);
v_current_maxval varchar2(3000);
---v1 tbl_part_manage_sql 修改为日志表。 记录执行时的日志。增加执行时的判断,记录报错信息。
---v2 考虑split分区的情况,
---v3 分区自动维护加分区会有问题。不再判断, 允许报错。
BEGIN
/*delete tbl_part_manage_sql;*/
v_hour := to_number(to_char(sysdate, 'HH24'));
select SEQ_TM_PART_MAINTEN.nextval into v_id from dual;
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'WEEK'
and p.partition_column_type = 'VARCHAR2'
and p.valid_flg IN (1, 3)
and v_hour >= p.shour
and v_hour < p.ehour) loop
v_tempname := rm.table_name;
v_currmax_date := null;
v_tempower := rm.table_owner;
v_current_maxval := null;
--- 获取分区最大值
v_isdefault := 'FALSE';
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 4000);
if v_high_value = 'MAXVALUE' then
v_isdefault := 'TRUE';
v_maxpart := cur_part.partition_name;
elsif v_current_maxval < v_high_value or v_current_maxval is null then
v_current_maxval := v_high_value;
end if;
end loop;
---transfer to date
if rm.format = 'YYYY-MM-DD' then
v_part_date := to_date(substr(v_current_maxval, 2, 10),
'YYYY-MM-DD');
elsif rm.format = 'YYYYMMDD' then
v_part_date := to_date(substr(v_current_maxval, 2, 8), 'YYYYMMDD');
end if;
v_currmax_date := v_part_date;
---如果配置表里表空间为空,找出该表目前所用表空间
if rm.tablespace_name is null then
/* select tablespace_name
into v_tablespace_name
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
and rownum = 1;*/
v_tablespace_name := '';
else
v_tablespace_name := ' tablespace ' || rm.tablespace_name;
end if;
---生成加分区SQL并执行。
while (v_currmax_date - rm.add_time_units * 7 <= trunc(sysdate)) loop
v_partname := to_char(trunc(v_currmax_date), 'YYYYMMDD');
if rm.format = 'YYYY-MM-DD' then
v_partdate := to_char(trunc(v_currmax_date) + 7, 'YYYY-MM-DD');
elsif rm.format = 'YYYYMMDD' then
v_partdate := to_char(trunc(v_currmax_date) + 7, 'YYYYMMDD');
end if;
v_currmax_date := v_currmax_date + 7;
select count(1)
into v_partition_cnt
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
and partition_name = rm.partition_pre || v_partname;
if (v_partition_cnt = 0) then
if v_isdefault = 'FALSE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' add partition ' || rm.partition_pre ||
v_partname || ' values less than (''' || v_partdate ||
''') ' || v_tablespace_name;
elsif v_isdefault = 'TRUE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' split partition ' || v_maxpart ||
' at (''' || v_partdate || ''' into (partition ' ||
rm.partition_pre || v_partname || ',partition ' ||
v_maxpart || ')';
end if;
---执行加分区的SQL
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
--如果配置了索引表空间索引,索引分区需rebuild到指定的索引表空间
if (rm.index_tb_name is not null) then
for cur_part_ind in (select distinct a.index_owner, a.index_name
/* a.index_owner,
a.index_name,
a.partition_name,
a.tablespace_name,
a.status*/
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and a.index_owner = rm.table_owner
/*and a.partition_name =
rm.partition_pre || v_partname*/
) loop
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
rm.partition_pre || v_partname || ' tablespace ' ||
rm.index_tb_name;
--- 执行SQL 重建索引
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end if;
end if;
end loop;
--重建不可用的局部索引
for cur_part_ind in (select a.index_owner,
a.index_name,
a.partition_name,
a.tablespace_name,
a.status
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and b.table_owner = rm.table_owner
and a.status = 'UNUSABLE') loop
begin
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
cur_part_ind.partition_name || ' tablespace ' ||
cur_part_ind.tablespace_name;
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
cur_part_ind.index_owner,
cur_part_ind.index_name,
cur_part_ind.partition_name,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end loop;
commit;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
---纪录异常日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempower,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
END STP_ADD_WEEK_VAR;
PROCEDURE STP_ADD_FIVE_DT AS
v_currmax_date date;
v_partdate varchar2(20);
v_high_value varchar2(4000);
v_partname varchar2(30);
v_part_date date;
v_tablespace_name varchar2(80);
v_partition_cnt number(10);
v_tempname varchar2(50);
v_id number;
v_isdefault varchar2(20);
v_sql varchar2(1000);
v_errmsg varchar2(1000);
v_maxpart varchar2(100);
v_tempower varchar2(100);
v_units number;
v_hour number(2);
---v1 tbl_part_manage_sql 修改为日志表。 记录执行时的日志。增加执行时的判断,记录报错信息。
---v2 考虑split分区的情况,
---v3 分区自动维护加分区会有问题。不再判断, 允许报错。
---v4 分区指定表空间对于子分区SQL 可能会报错。修改未指定表空间的分区SQL不指定表空间。
BEGIN
/*delete tbl_part_manage_sql;*/
v_hour := to_number(to_char(sysdate, 'HH24'));
select SEQ_TM_PART_MAINTEN.nextval into v_id from dual;
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'FIVE'
and p.partition_column_type = 'DATE'
and p.valid_flg in (1, 3)
and v_hour >= p.shour
and v_hour < p.ehour) loop
v_tempname := rm.table_name;
v_maxpart := null;
v_tempower := rm.table_owner;
v_units := trunc(TO_NUMBER(TO_CHAR(sysdate, 'DD')) / 5) + 1 +
rm.add_time_units;
--- 获取分区最大值
v_currmax_date := null;
v_isdefault := 'FALSE';
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 4000);
--- 判断是否存在MAXVALUE, 如果存在则只能使用SPLIT分区,记录DEFAULT 分区名字
if v_high_value = 'MAXVALUE' then
v_isdefault := 'TRUE';
v_maxpart := cur_part.partition_name;
else
execute immediate 'select ' || v_high_value || ' from dual'
into v_part_date;
if v_currmax_date <= v_part_date or v_currmax_date is null then
v_currmax_date := v_part_date;
end if;
end if;
end loop;
---如果配置表里表空间为空,不指定表空间参数
if rm.tablespace_name is null then
v_tablespace_name := '';
else
v_tablespace_name := ' tablespace ' || rm.tablespace_name;
end if;
---生成加分区SQL并执行。
while (v_currmax_date <=
add_months(trunc(sysdate, 'MM'), trunc(v_units / 6)) +
mod(v_units, 6) * 5) loop
if trunc(to_number(to_char(v_currmax_date, 'DD')) / 5) = 0 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'A';
v_partdate := TO_CHAR(trunc(v_currmax_date + 5),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := v_currmax_date + 5;
elsif trunc(to_number(to_char(v_currmax_date, 'DD')) / 5) = 1 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'B';
v_partdate := TO_CHAR(trunc(v_currmax_date + 5),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := v_currmax_date + 5;
elsif trunc(to_number(to_char(v_currmax_date, 'DD')) / 5) = 2 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'C';
v_partdate := TO_CHAR(trunc(v_currmax_date + 5),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := v_currmax_date + 5;
elsif trunc(to_number(to_char(v_currmax_date, 'DD')) / 5) = 3 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'D';
v_partdate := TO_CHAR(trunc(v_currmax_date + 5),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := v_currmax_date + 5;
elsif trunc(to_number(to_char(v_currmax_date, 'DD')) / 5) = 4 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'E';
v_partdate := TO_CHAR(trunc(v_currmax_date + 5),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := v_currmax_date + 5;
elsif trunc(to_number(to_char(v_currmax_date, 'DD')) / 5) = 5 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'F';
v_partdate := TO_CHAR(ADD_MONTHS(trunc(v_currmax_date, 'MM'),
1),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := ADD_MONTHS(trunc(v_currmax_date, 'MM'), 1);
end if;
select count(1)
into v_partition_cnt
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
and partition_name = rm.partition_pre || v_partname;
if (v_partition_cnt = 0) then
if v_isdefault = 'FALSE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' add partition ' || rm.partition_pre ||
v_partname || ' values less than (to_date(''' ||
v_partdate || ''',''YYYY-MM-DD HH24:MI:SS''))' ||
v_tablespace_name;
elsif v_isdefault = 'TRUE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' split partition ' || v_maxpart ||
' at (to_date(''' || v_partdate ||
''', ''YYYY-MM-DD HH24:MI:SS'')) into (partition ' ||
rm.partition_pre || v_partname || ',partition ' ||
v_maxpart || ')';
end if;
---执行加分区的SQL
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
COMMIT;
--如果配置了索引表空间索引,索引分区需rebuild到指定的索引表空间
if (rm.index_tb_name is not null) then
for cur_part_ind in (select distinct a.index_owner, a.index_name
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and a.index_owner = rm.table_owner) loop
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
rm.partition_pre || v_partname || ' tablespace ' ||
rm.index_tb_name;
--- 执行SQL 重建索引
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end if;
end if;
end loop;
end loop;
end STP_ADD_FIVE_DT;
PROCEDURE STP_ADD_FIVE_VAR AS
v_currmax_date date;
v_partdate varchar2(20);
v_high_value varchar2(4000);
v_partname varchar2(30);
v_part_date date;
v_tablespace_name varchar2(80);
v_partition_cnt number(10);
v_tempname varchar2(50);
v_id number;
v_isdefault varchar2(20);
v_sql varchar2(1000);
v_errmsg varchar2(1000);
v_maxpart varchar2(100);
v_tempower varchar2(100);
v_units number;
v_hour number(2);
v_current_maxval varchar2(3000);
---v1 tbl_part_manage_sql 修改为日志表。 记录执行时的日志。增加执行时的判断,记录报错信息。
---v2 考虑split分区的情况,
---v3 对于11G 的新建分区不做判断, 直接处理。
BEGIN
/*delete tbl_part_manage_sql;*/
v_hour := to_number(to_char(sysdate, 'HH24'));
select SEQ_TM_PART_MAINTEN.nextval into v_id from dual;
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'FIVE'
and p.partition_column_type = 'VARCHAR2'
and p.valid_flg IN (1, 3)
and v_hour >= p.shour
and v_hour < p.ehour) loop
v_tempname := rm.table_name;
v_tempower := rm.table_owner;
v_current_maxval := null;
--- 获取分区最大值
v_isdefault := 'FALSE';
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 4000);
--- 判断是否存在MAXVALUE, 如果存在则只能使用SPLIT分区,记录DEFAULT 分区名字
if v_high_value = 'MAXVALUE' then
v_isdefault := 'TRUE';
v_maxpart := cur_part.partition_name;
elsif v_current_maxval < v_high_value or v_current_maxval is null then
v_current_maxval := v_high_value;
end if;
end loop;
---transfer to date
if rm.format = 'YYYY-MM-DD' then
v_part_date := to_date(substr(v_current_maxval, 2, 10),
'YYYY-MM-DD');
elsif rm.format = 'YYYYMMDD' then
v_part_date := to_date(substr(v_current_maxval, 2, 8), 'YYYYMMDD');
end if;
v_currmax_date := v_part_date;
---如果配置表里表空间为空,找出该表目前所用表空间
if rm.tablespace_name is null then
/* select tablespace_name
into v_tablespace_name
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
and rownum = 1;*/
v_tablespace_name := '';
else
v_tablespace_name := ' tablespace ' || rm.tablespace_name;
end if;
---生成加分区SQL并执行。
v_units := trunc(TO_NUMBER(TO_CHAR(sysdate, 'DD')) / 5) + 1 +
rm.add_time_units;
while (v_currmax_date - rm.add_time_units <=
add_months(trunc(sysdate, 'MM'), trunc(v_units / 6)) +
mod(v_units, 6) * 10) loop
if trunc(to_number(to_char(v_currmax_date, 'DD')) / 5) = 0 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'A';
v_partdate := TO_CHAR(trunc(v_currmax_date + 5),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := v_currmax_date + 5;
elsif trunc(to_number(to_char(v_currmax_date, 'DD')) / 5) = 1 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'B';
v_partdate := TO_CHAR(trunc(v_currmax_date + 5),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := v_currmax_date + 5;
elsif trunc(to_number(to_char(v_currmax_date, 'DD')) / 5) = 2 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'C';
v_partdate := TO_CHAR(trunc(v_currmax_date + 5),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := v_currmax_date + 5;
elsif trunc(to_number(to_char(v_currmax_date, 'DD')) / 5) = 3 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'D';
v_partdate := TO_CHAR(trunc(v_currmax_date + 5),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := v_currmax_date + 5;
elsif trunc(to_number(to_char(v_currmax_date, 'DD')) / 5) = 4 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'E';
v_partdate := TO_CHAR(trunc(v_currmax_date + 5),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := v_currmax_date + 5;
elsif trunc(to_number(to_char(v_currmax_date, 'DD')) / 5) = 5 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'F';
v_partdate := TO_CHAR(ADD_MONTHS(trunc(v_currmax_date, 'MM'),
1),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := ADD_MONTHS(trunc(v_currmax_date, 'MM'), 1);
end if;
if rm.format = 'YYYY-MM-DD' then
v_partdate := to_char(trunc(v_currmax_date), 'YYYY-MM-DD');
elsif rm.format = 'YYYYMMDD' then
v_partdate := to_char(trunc(v_currmax_date), 'YYYYMMDD');
end if;
select count(1)
into v_partition_cnt
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
and partition_name = rm.partition_pre || v_partname;
if (v_partition_cnt = 0) then
if v_isdefault = 'FALSE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' add partition ' || rm.partition_pre ||
v_partname || ' values less than (''' || v_partdate ||
''') ' || v_tablespace_name;
elsif v_isdefault = 'TRUE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' split partition ' || v_maxpart ||
' at (''' || v_partdate || ''' into (partition ' ||
rm.partition_pre || v_partname || ',partition ' ||
v_maxpart || ')';
end if;
---执行加分区的SQL
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
--如果配置了索引表空间索引,索引分区需rebuild到指定的索引表空间
if (rm.index_tb_name is not null) then
for cur_part_ind in (select distinct a.index_owner, a.index_name
/* a.index_owner,
a.index_name,
a.partition_name,
a.tablespace_name,
a.status*/
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and a.index_owner = rm.table_owner
/*and a.partition_name =
rm.partition_pre || v_partname*/
) loop
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
rm.partition_pre || v_partname || ' tablespace ' ||
rm.index_tb_name;
--- 执行SQL 重建索引
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end if;
end if;
end loop;
--重建不可用的局部索引
for cur_part_ind in (select a.index_owner,
a.index_name,
a.partition_name,
a.tablespace_name,
a.status
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and b.table_owner = rm.table_owner
and a.status = 'UNUSABLE') loop
begin
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
cur_part_ind.partition_name || ' tablespace ' ||
cur_part_ind.tablespace_name;
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
cur_part_ind.index_owner,
cur_part_ind.index_name,
cur_part_ind.partition_name,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end loop;
commit;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
---纪录异常日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempower,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
END STP_ADD_FIVE_VAR;
PROCEDURE STP_DEL_WEEK AS
v_currmax_date date;
v_high_value varchar2(4000);
v_part_date date;
v_drop_date date;
v_id number;
v_sql varchar2(1000);
v_errmsg varchar2(1000);
v_tempowner varchar2(100);
v_tempname varchar2(50);
v_partname varchar2(50);
v_partdate varchar2(20);
v_hour number(2);
v_dropvalue varchar2(40);
v_count NUMBER;
BEGIN
/*delete tbl_part_manage_sql;*/
v_hour := to_number(to_char(sysdate, 'HH24'));
select SEQ_TM_PART_MAINTEN.nextval into v_id from dual;
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'WEEK'
and p.partition_column_type = 'DATE'
and p.valid_flg in (1, 4)
and v_hour >= p.shour
and v_hour < p.ehour) loop
v_tempname := rm.table_name;
v_tempowner := rm.table_owner;
v_currmax_date := null;
v_drop_date := trunc(sysdate) - rm.drop_time_units * 7;
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 4000);
if v_high_value = 'MAXVALUE' then
null;
else
execute immediate 'select ' || v_high_value || ' from dual'
into v_part_date;
if v_drop_date >= v_part_date then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' drop partition ' ||
cur_part.partition_name;
v_partname := cur_part.partition_name;
v_partdate := to_char(v_part_date, 'YYYY-MM-DD');
select count(*)
into v_count
from dba_indexes t
where t.table_owner = RM.TABLE_OWNER
AND T.table_name = rm.table_name
and PARTITIONED = 'NO';
begin
if rm.config_Type = 'TEST' and v_count = 0 then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' and v_count = 0 then
v_errmsg := 'OK';
execute immediate v_sql;
else
v_errmsg := 'GLOBAL_INDEXES';
v_sql:=v_sql||' UPDATE GLOBAL INDEXES';
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempowner,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end if;
end if;
end loop;
end loop;
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'WEEK'
and p.partition_column_type = 'VARCHAR2'
and p.valid_flg in (1, 4)) loop
v_tempname := rm.table_name;
v_currmax_date := null;
v_drop_date := trunc(sysdate) - rm.drop_time_units * 7;
if rm.format = 'YYYY-MM-DD' THEN
v_dropvalue := ''''||to_char(v_drop_date, 'YYYY-MM-DD')||'''';
elsif rm.format = 'YYYYMMDD' THEN
v_dropvalue := ''''||to_char(v_drop_date, 'YYYYMMDD')||'''';
end if;
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 2000);
if v_high_value = 'MAXVALUE' then
null;
else
if v_dropvalue > v_high_value then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' drop partition ' ||
cur_part.partition_name;
v_partname := cur_part.partition_name;
v_partdate := v_high_value;
select count(*)
into v_count
from dba_indexes t
where t.table_owner = RM.TABLE_OWNER
AND T.table_name = rm.table_name
and PARTITIONED = 'NO';
begin
if rm.config_Type = 'TEST' and v_count = 0 then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' and v_count = 0 then
v_errmsg := 'OK';
execute immediate v_sql;
else
v_errmsg := 'GLOBAL_INDEXES';
v_sql:=v_sql||' UPDATE GLOBAL INDEXES';
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempowner,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end if;
end if;
end loop;
end loop;
commit;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempowner,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
END STP_DEL_WEEK;
PROCEDURE STP_ADD_TEN_DT AS
v_currmax_date date;
v_partdate varchar2(20);
v_high_value varchar2(4000);
v_partname varchar2(30);
v_part_date date;
v_tablespace_name varchar2(80);
v_partition_cnt number(10);
v_tempname varchar2(50);
v_id number;
v_isdefault varchar2(20);
v_sql varchar2(1000);
v_errmsg varchar2(1000);
v_maxpart varchar2(100);
v_tempower varchar2(100);
v_units number;
v_hour number(2);
---v1 tbl_part_manage_sql 修改为日志表。 记录执行时的日志。增加执行时的判断,记录报错信息。
---v2 考虑split分区的情况,
---v3 分区自动维护加分区会有问题。不再判断, 允许报错。
---v4 分区指定表空间对于子分区SQL 可能会报错。修改未指定表空间的分区SQL不指定表空间。
BEGIN
/*delete tbl_part_manage_sql;*/
v_hour := to_number(to_char(sysdate, 'HH24'));
select SEQ_TM_PART_MAINTEN.nextval into v_id from dual;
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'TEN'
and p.partition_column_type = 'DATE'
and p.valid_flg in (1, 3)
and v_hour >= p.shour
and v_hour < p.ehour) loop
v_tempname := rm.table_name;
v_maxpart := null;
v_tempower := rm.table_owner;
v_units := trunc(TO_NUMBER(TO_CHAR(sysdate, 'DD')) / 10) + 1 +
rm.add_time_units;
--- 获取分区最大值
v_currmax_date := null;
v_isdefault := 'FALSE';
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 4000);
--- 判断是否存在MAXVALUE, 如果存在则只能使用SPLIT分区,记录DEFAULT 分区名字
if v_high_value = 'MAXVALUE' then
v_isdefault := 'TRUE';
v_maxpart := cur_part.partition_name;
else
execute immediate 'select ' || v_high_value || ' from dual'
into v_part_date;
if v_currmax_date <= v_part_date or v_currmax_date is null then
v_currmax_date := v_part_date;
end if;
end if;
end loop;
---如果配置表里表空间为空,不指定表空间参数
if rm.tablespace_name is null then
v_tablespace_name := '';
else
v_tablespace_name := ' tablespace ' || rm.tablespace_name;
end if;
---生成加分区SQL并执行。
while (v_currmax_date <=
add_months(trunc(sysdate, 'MM'), trunc(v_units / 3)) +
mod(v_units, 3) * 10) loop
if trunc(to_number(to_char(v_currmax_date, 'DD')) / 10) = 0 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'A';
v_partdate := TO_CHAR(trunc(v_currmax_date + 10),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := v_currmax_date + 10;
elsif trunc(to_number(to_char(v_currmax_date, 'DD')) / 10) = 1 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'B';
v_partdate := TO_CHAR(trunc(v_currmax_date + 10),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := v_currmax_date + 10;
elsif trunc(to_number(to_char(v_currmax_date, 'DD')) / 10) = 2 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'C';
v_partdate := TO_CHAR(ADD_MONTHS(trunc(v_currmax_date, 'MM'),
1),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := ADD_MONTHS(trunc(v_currmax_date, 'MM'), 1);
end if;
select count(1)
into v_partition_cnt
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
and partition_name = rm.partition_pre || v_partname;
if (v_partition_cnt = 0) then
if v_isdefault = 'FALSE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' add partition ' || rm.partition_pre ||
v_partname || ' values less than (to_date(''' ||
v_partdate || ''',''YYYY-MM-DD HH24:MI:SS''))' ||
v_tablespace_name;
elsif v_isdefault = 'TRUE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' split partition ' || v_maxpart ||
' at (to_date(''' || v_partdate ||
''', ''YYYY-MM-DD HH24:MI:SS'')) into (partition ' ||
rm.partition_pre || v_partname || ',partition ' ||
v_maxpart || ')';
end if;
---执行加分区的SQL
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
--如果配置了索引表空间索引,索引分区需rebuild到指定的索引表空间
if (rm.index_tb_name is not null) then
for cur_part_ind in (select distinct a.index_owner, a.index_name
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and a.index_owner = rm.table_owner) loop
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
rm.partition_pre || v_partname || ' tablespace ' ||
rm.index_tb_name;
--- 执行SQL 重建索引
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end if;
end if;
end loop;
--重建不可用的局部索引
for cur_part_ind in (select a.index_owner,
a.index_name,
a.partition_name,
a.tablespace_name,
a.status
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and b.table_owner = rm.table_owner
and a.status = 'UNUSABLE') loop
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
cur_part_ind.partition_name || ' tablespace ' ||
cur_part_ind.tablespace_name;
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
cur_part_ind.index_owner,
cur_part_ind.index_name,
cur_part_ind.partition_name,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end loop;
commit;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempower,
v_tempower,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
END STP_ADD_TEN_DT;
PROCEDURE STP_ADD_TEN_VAR AS
v_currmax_date date;
v_partdate varchar2(20);
v_high_value varchar2(4000);
v_partname varchar2(30);
v_part_date date;
v_tablespace_name varchar2(80);
v_partition_cnt number(10);
v_tempname varchar2(50);
v_id number;
v_isdefault varchar2(20);
v_sql varchar2(1000);
v_errmsg varchar2(1000);
v_maxpart varchar2(100);
v_tempower varchar2(100);
v_units number;
v_hour number(2);
v_current_maxval varchar2(3000);
---v1 tbl_part_manage_sql 修改为日志表。 记录执行时的日志。增加执行时的判断,记录报错信息。
---v2 考虑split分区的情况,
---v3 对于11G 的新建分区不做判断, 直接处理。
BEGIN
/*delete tbl_part_manage_sql;*/
v_hour := to_number(to_char(sysdate, 'HH24'));
select SEQ_TM_PART_MAINTEN.nextval into v_id from dual;
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'TEN'
and p.partition_column_type = 'VARCHAR2'
and p.valid_flg IN (1, 3)
and v_hour >= p.shour
and v_hour < p.ehour) loop
v_tempname := rm.table_name;
v_tempower := rm.table_owner;
v_current_maxval := null;
--- 获取分区最大值
v_isdefault := 'FALSE';
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 4000);
--- 判断是否存在MAXVALUE, 如果存在则只能使用SPLIT分区,记录DEFAULT 分区名字
if v_high_value = 'MAXVALUE' then
v_isdefault := 'TRUE';
v_maxpart := cur_part.partition_name;
elsif v_current_maxval < v_high_value or v_current_maxval is null then
v_current_maxval := v_high_value;
end if;
end loop;
---transfer to date
if rm.format = 'YYYY-MM-DD' then
v_part_date := to_date(substr(v_current_maxval, 2, 10),
'YYYY-MM-DD');
elsif rm.format = 'YYYYMMDD' then
v_part_date := to_date(substr(v_current_maxval, 2, 8), 'YYYYMMDD');
end if;
v_currmax_date := v_part_date;
---如果配置表里表空间为空,找出该表目前所用表空间
if rm.tablespace_name is null then
/* select tablespace_name
into v_tablespace_name
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
and rownum = 1;*/
v_tablespace_name := '';
else
v_tablespace_name := ' tablespace ' || rm.tablespace_name;
end if;
---生成加分区SQL并执行。
v_units := trunc(TO_NUMBER(TO_CHAR(sysdate, 'DD')) / 10) + 1 +
rm.add_time_units;
while (v_currmax_date - rm.add_time_units <=
add_months(trunc(sysdate, 'MM'), trunc(v_units / 3)) +
mod(v_units, 3) * 10) loop
if trunc(to_number(to_char(v_currmax_date, 'DD')) / 10) = 0 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'A';
v_partdate := TO_CHAR(trunc(v_currmax_date + 10),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := v_currmax_date + 10;
elsif trunc(to_number(to_char(v_currmax_date, 'DD')) / 10) = 1 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'B';
v_partdate := TO_CHAR(trunc(v_currmax_date + 10),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := v_currmax_date + 10;
elsif trunc(to_number(to_char(v_currmax_date, 'DD')) / 10) = 2 then
v_partname := to_char(trunc(v_currmax_date), 'YYYYMM') || 'C';
v_partdate := TO_CHAR(ADD_MONTHS(trunc(v_currmax_date, 'MM'),
1),
'YYYY-MM-DD HH24:MI:SS');
v_currmax_date := ADD_MONTHS(trunc(v_currmax_date, 'MM'), 1);
end if;
if rm.format = 'YYYY-MM-DD' then
v_partdate := to_char(trunc(v_currmax_date), 'YYYY-MM-DD');
elsif rm.format = 'YYYYMMDD' then
v_partdate := to_char(trunc(v_currmax_date), 'YYYYMMDD');
end if;
select count(1)
into v_partition_cnt
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
and partition_name = rm.partition_pre || v_partname;
if (v_partition_cnt = 0) then
if v_isdefault = 'FALSE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' add partition ' || rm.partition_pre ||
v_partname || ' values less than (''' || v_partdate ||
''') ' || v_tablespace_name;
elsif v_isdefault = 'TRUE' then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' split partition ' || v_maxpart ||
' at (''' || v_partdate || ''' into (partition ' ||
rm.partition_pre || v_partname || ',partition ' ||
v_maxpart || ')';
end if;
---执行加分区的SQL
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
--如果配置了索引表空间索引,索引分区需rebuild到指定的索引表空间
if (rm.index_tb_name is not null) then
for cur_part_ind in (select distinct a.index_owner, a.index_name
/* a.index_owner,
a.index_name,
a.partition_name,
a.tablespace_name,
a.status*/
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and a.index_owner = rm.table_owner
/*and a.partition_name =
rm.partition_pre || v_partname*/
) loop
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
rm.partition_pre || v_partname || ' tablespace ' ||
rm.index_tb_name;
--- 执行SQL 重建索引
begin
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
rm.table_owner,
rm.table_name,
rm.partition_pre || v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end if;
end if;
end loop;
--重建不可用的局部索引
for cur_part_ind in (select a.index_owner,
a.index_name,
a.partition_name,
a.tablespace_name,
a.status
from dba_ind_partitions a, dba_indexes b
where a.index_owner = b.owner
and a.index_name = b.index_name
and b.table_name = rm.table_name
and b.table_owner = rm.table_owner
and a.status = 'UNUSABLE') loop
begin
v_sql := 'alter index ' || cur_part_ind.index_owner || '.' ||
cur_part_ind.index_name || ' rebuild partition ' ||
cur_part_ind.partition_name || ' tablespace ' ||
cur_part_ind.tablespace_name;
if rm.config_Type = 'TEST' then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' then
v_errmsg := 'OK';
execute immediate v_sql;
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
cur_part_ind.index_owner,
cur_part_ind.index_name,
cur_part_ind.partition_name,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end loop;
end loop;
commit;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
---纪录异常日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempower,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
END STP_ADD_TEN_VAR;
PROCEDURE STP_DEL_TEN AS
v_currmax_date date;
v_high_value varchar2(4000);
v_part_date date;
v_drop_date date;
v_id number;
v_sql varchar2(1000);
v_errmsg varchar2(1000);
v_tempowner varchar2(100);
v_tempname varchar2(50);
v_partname varchar2(50);
v_partdate varchar2(20);
v_units number;
v_hour number(2);
v_dropval varchar2(40);
v_count NUMBER;
BEGIN
/*delete tbl_part_manage_sql;*/
v_hour := to_number(to_char(sysdate, 'HH24'));
select SEQ_TM_PART_MAINTEN.nextval into v_id from dual;
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'TEN'
and p.partition_column_type = 'DATE'
and p.valid_flg in (1, 4)
and v_hour >= p.shour
and v_hour < p.ehour) loop
v_tempname := rm.table_name;
v_tempowner := rm.table_owner;
v_currmax_date := null;
---获取需删除分区的最大日期
v_units := trunc(TO_NUMBER(TO_CHAR(sysdate, 'DD')) / 10) + 1 -
rm.drop_time_units;
if v_units < 0 then
v_drop_date := ADD_MONTHS(trunc(sysdate, 'MM'),
trunc(v_units / 3) - 1) +
(mod(v_units, 3) + 3) * 10;
elsif v_units >= 0 then
v_drop_date := trunc(sysdate, 'MM') + v_units * 10;
end if;
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 4000);
if v_high_value = 'MAXVALUE' then
null;
else
execute immediate 'select ' || v_high_value || ' from dual'
into v_part_date;
if v_drop_date >= v_part_date then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' drop partition ' ||
cur_part.partition_name;
v_partname := cur_part.partition_name;
v_partdate := to_char(v_part_date, 'YYYY-MM-DD');
select count(*)
into v_count
from dba_indexes t
where t.table_owner = RM.TABLE_OWNER
AND T.table_name = rm.table_name
and PARTITIONED = 'NO';
begin
if rm.config_Type = 'TEST' and v_count = 0 then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' and v_count = 0 then
v_errmsg := 'OK';
execute immediate v_sql;
else
v_errmsg := 'GLOBAL_INDEXES';
v_sql:=v_sql||' UPDATE GLOBAL INDEXES';
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempowner,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end if;
end if;
end loop;
end loop;
for rm in (select distinct p.*
from tbl_tab_part_config p, dba_tab_partitions u
where p.table_owner = u.table_owner
and p.table_name = u.table_name
and p.partition_type = 'TEN'
and p.partition_column_type = 'VARCHAR2'
and p.valid_flg in (1, 4)) loop
v_tempname := rm.table_name;
v_currmax_date := null;
----获取分区最大日期的类型
v_units := trunc(TO_NUMBER(TO_CHAR(sysdate, 'DD')) / 10) + 1 -
rm.drop_time_units;
if v_units < 0 then
v_drop_date := ADD_MONTHS(trunc(sysdate, 'MM'),
trunc(v_units / 3) - 1) +
(mod(v_units, 3) + 3) * 10;
elsif v_units >= 0 then
v_drop_date := trunc(sysdate, 'MM') + v_units * 10;
end if;
if rm.format = 'YYYY-MM-DD' THEN
v_dropval := ''''||to_char(v_drop_date, 'YYYY-MM-DD')||'''';
elsif rm.format = 'YYYYMMDD' THEN
v_dropval := ''''||to_char(v_drop_date, 'YYYYMMDD')||'''';
end if;
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = rm.table_owner
and table_name = rm.table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 2000);
if v_high_value = 'MAXVALUE' then
null;
else
if v_dropval >= v_high_value then
v_sql := 'alter table ' || rm.table_owner || '.' ||
rm.table_name || ' drop partition ' ||
cur_part.partition_name;
v_partname := cur_part.partition_name;
v_partdate := v_high_value;
select count(*)
into v_count
from dba_indexes t
where t.table_owner = RM.TABLE_OWNER
AND T.table_name = rm.table_name
and PARTITIONED = 'NO';
begin
if rm.config_Type = 'TEST' and v_count = 0 then
v_errmsg := 'TEST';
elsif rm.config_type = 'RUN' and v_count = 0 then
v_errmsg := 'OK';
execute immediate v_sql;
else
v_errmsg := 'GLOBAL_INDEXES';
v_sql:=v_sql||' UPDATE GLOBAL INDEXES';
end if;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
end;
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempowner,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
end if;
end if;
end loop;
end loop;
commit;
exception
when others then
v_errmsg := substr(sqlerrm, 1, 60);
---纪录操作日志
insert into TBL_PART_MANAGE_SQL
(gid,
table_owner,
table_name,
partition_name,
max_date,
sql_text,
create_time,
order_id,
resultmsg)
values
(v_id,
v_tempowner,
v_tempname,
v_partname,
v_partdate,
v_sql || ';',
sysdate,
seq_sql_order.nextval,
v_errmsg);
commit;
END STP_DEL_TEN;
PROCEDURE GATHER_TABLE_INFO(v_table_owner in varchar2,
v_table_name in varchar2) AS
v_high_value varchar2(4000);
v_isdefault varchar2(30);
v_maxpart varchar2(60);
v_minpart varchar2(60);
v_part_time date;
v_partmaxdate varchar2(12);
v_part2stdate varchar2(12);
v_partmindate varchar2(12);
v_current_maxval varchar2(3000);
v_current_minval varchar2(3000);
v_current_2stval varchar2(3000);
v_partcol_type varchar2(20);
v_part_type varchar2(10);
v_format varchar2(12);
v_gi_count number;
v_partcol_name varchar2(100);
v_count number;
v_interval varchar2(30);
BEGIN
delete dbamon.tbl_part_info
where table_owner = v_table_owner
and table_name = v_table_name;
v_isdefault := 'FALSE';
v_current_maxval := null;
v_current_minval := null;
v_current_2stval := null;
select count(*)
into v_gi_count
from dba_indexes t
where t.table_owner = v_table_owner
and t.table_name = v_table_name
and t.partitioned <> 'YES';
for cur_part in (select partition_name, high_value
from dba_tab_partitions
where table_owner = v_table_owner
and table_name = v_table_name
order by partition_name) loop
v_high_value := substr(cur_part.high_value, 1, 4000);
if v_high_value = 'MAXVALUE' then
v_isdefault := 'TRUE';
else
if v_current_maxval is null then
v_current_maxval := v_high_value;
v_maxpart := cur_part.partition_name;
elsif v_current_maxval < v_high_value then
v_current_2stval := v_current_maxval;
v_current_maxval := v_high_value;
v_maxpart := cur_part.partition_name;
elsif v_current_2stval < v_high_value then
v_current_2stval := v_high_value;
end if;
if v_current_minval is null or v_current_minval >= v_high_value then
v_current_minval := v_high_value;
v_minpart := cur_part.partition_name;
end if;
end if;
end loop;
v_format := null;
v_partmaxdate := null;
v_partmindate := null;
v_part2stdate := null;
SELECT DATA_TYPE, t1.COLUMN_NAME
INTO v_partcol_type, v_partcol_name
fROM DBA_TAB_COLUMNS T1, DBA_PART_KEY_COLUMNS T2
WHERE T1.OWNER = T2.OWNER
AND T1.TABLE_NAME = T2.NAME
AND T1.COLUMN_NAME = T2.COLUMN_NAME
AND T1.TABLE_NAME = v_table_name
AND T1.OWNER = v_table_owner
and rownum < 2;
/* select count(*) into v_count from v$instance where version like '11%';*/
v_count:=1;
if v_count > 0 then
execute immediate 'select interval from dba_part_tables
where owner=''' || v_table_owner ||
''' and table_name=''' || v_table_name || ''''
into v_interval;
else
v_interval := null;
end if;
if v_partcol_type = 'DATE' or v_partcol_type like 'TIMESTAMP%' then
execute immediate 'select ' || v_current_maxval || ' from dual'
into v_part_time;
v_partmaxdate := to_char(v_part_time, 'YYYY-MM-DD');
execute immediate 'select ' || v_current_minval || ' from dual'
into v_part_time;
v_partmindate := to_char(v_part_time, 'YYYY-MM-DD');
if v_current_2stval is not null then
execute immediate 'select ' || v_current_2stval || ' from dual'
into v_part_time;
v_part2stdate := to_char(v_part_time, 'YYYY-MM-DD');
end if;
elsif v_partcol_type = 'VARCHAR2' OR v_partcol_type = 'VARCHAR' or
v_partcol_type = 'CHAR' then
if length(v_current_maxval) = 9 and
substr(v_current_maxval, 6, 1) = '-' then
v_format := 'YYYY-MM';
v_partmaxdate := REPLACE(v_current_maxval, '''', NULL) || '-01';
elsif length(v_current_maxval) = 8 and
instr(v_current_maxval, '-') = 0 then
v_format := 'YYYYMM';
v_partmaxdate := substr(v_current_maxval, 2, 4) || '-' ||
substr(v_current_maxval, 6, 2) || '-01';
elsif length(v_current_maxval) = 12 and
substr(v_current_maxval, 6, 1) = '-' and
substr(v_current_maxval, 9, 1) = '-' then
v_format := 'YYYY-MM-DD';
v_partmaxdate := replace(v_current_maxval, '''', '');
elsif length(v_current_maxval) = 10 and
instr(v_current_maxval, '-') = 0 then
v_format := 'YYYYMMDD';
v_partmaxdate := substr(v_current_maxval, 2, 4) || '-' ||
substr(v_current_maxval, 6, 2) || '-' ||
substr(v_current_maxval, 8, 2);
end if;
if length(v_current_minval) = 9 and
substr(v_current_minval, 6, 1) = '-' then
v_partmindate := REPLACE(v_current_minval, '''', NULL) || '-01';
elsif length(v_current_minval) = 8 and
instr(v_current_minval, '-') = 0 then
v_partmindate := substr(v_current_minval, 2, 4) || '-' ||
substr(v_current_minval, 6, 2) || '-01';
elsif length(v_current_minval) = 12 and
substr(v_current_minval, 6, 1) = '-' and
substr(v_current_minval, 9, 1) = '-' then
v_partmindate := replace(v_current_minval, '''', '');
elsif length(v_current_minval) = 10 and
instr(v_current_minval, '-') = 0 then
v_partmindate := substr(v_current_minval, 2, 4) || '-' ||
substr(v_current_minval, 6, 2) || '-' ||
substr(v_current_minval, 8, 2);
end if;
if length(v_current_2stval) = 9 and
substr(v_current_2stval, 6, 1) = '-' then
v_part2stdate := REPLACE(v_current_2stval, '''', NULL) || '-01';
elsif length(v_current_2stval) = 8 and
instr(v_current_2stval, '-') = 0 then
v_part2stdate := substr(v_current_2stval, 2, 4) || '-' ||
substr(v_current_2stval, 6, 2) || '-01';
elsif length(v_current_2stval) = 12 and
substr(v_current_2stval, 6, 1) = '-' and
substr(v_current_2stval, 9, 1) = '-' then
v_part2stdate := replace(v_current_2stval, '''', '');
elsif length(v_current_2stval) = 10 and
instr(v_current_2stval, '-') = 0 then
v_part2stdate := substr(v_current_2stval, 2, 4) || '-' ||
substr(v_current_2stval, 6, 2) || '-' ||
substr(v_current_2stval, 8, 2);
end if;
end if;
v_part_type := null;
if v_partmaxdate is not null and v_part2stdate is not null then
if to_date(v_partmaxdate, 'yyyy-mm-dd') =
add_months(TO_DATE(v_part2stdate, 'YYYY-MM-DD'), 1) THEN
v_part_type := 'MONTH';
elsif to_date(v_partmaxdate, 'yyyy-mm-dd') =
TO_DATE(v_part2stdate, 'YYYY-MM-DD') + 1 then
v_part_type := 'DAY';
elsif to_date(v_partmaxdate, 'yyyy-mm-dd') =
TO_DATE(v_part2stdate, 'YYYY-MM-DD') + 7 then
v_part_type := 'WEEK';
elsif to_date(v_partmaxdate, 'yyyy-mm-dd') -
TO_DATE(v_part2stdate, 'YYYY-MM-DD') in (8, 10, 11) then
v_part_type := 'TEN';
elsif to_date(v_partmaxdate, 'yyyy-mm-dd') =
add_months(TO_DATE(v_part2stdate, 'YYYY-MM-DD'), 1) then
v_part_type := 'YEAR';
elsif to_date(v_partmaxdate, 'yyyy-mm-dd') -
TO_DATE(v_part2stdate, 'YYYY-MM-DD') in (5,6) then
v_part_type := 'FIVE';
else
v_part_type := to_date(v_partmaxdate, 'yyyy-mm-dd') -
TO_DATE(v_part2stdate, 'YYYY-MM-DD');
end if;
end if;
insert into dbamon.tBL_part_Info
values
(v_table_owner,
v_table_name,
v_minpart,
v_maxpart,
v_partmindate,
v_partmaxdate,
v_current_minval,
v_current_maxval,
v_partcol_type,
sysdate,
v_isdefault,
v_format,
v_part_type,
v_gi_count,
v_partcol_name,
v_interval);
commit;
end GATHER_TABLE_INFO;
PROCEDURE GATHER_PARTITION_INFO AS
begin
delete dbamon.tbl_part_info;
commit;
for rm in (select *
from DBA_PART_TABLES t
WHERE T.OWNER NOT IN ('SYS', 'SYSTEM')
and t.partitioning_type = 'RANGE'
and t.table_name not like 'BIN$%') loop
GATHER_table_INFO(rm.owner, rm.table_name);
end loop;
end GATHER_PARTITION_INFO;
PROCEDURE ADD_ALL_PART AS
PROC_NAME VARCHAR2(100);
ERRMSG VARCHAR2(100);
BEGIN
PROC_NAME := 'STP_ADD_DAY_DT';
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'START', SYSDATE);
COMMIT;
STP_ADD_DAY_DT;
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'END', SYSDATE);
COMMIT;
PROC_NAME := 'STP_ADD_DAY_VAR';
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'START', SYSDATE);
COMMIT;
STP_ADD_DAY_VAR;
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'END', SYSDATE);
COMMIT;
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'END', SYSDATE);
PROC_NAME := 'STP_ADD_FIVE_DT';
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'START', SYSDATE);
STP_ADD_FIVE_DT;
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'END', SYSDATE);
COMMIT;
PROC_NAME := 'STP_ADD_FIVE_VAR';
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'START', SYSDATE);
STP_ADD_FIVE_VAR;
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'END', SYSDATE);
COMMIT;
PROC_NAME := 'STP_ADD_WEEK_DT';
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'START', SYSDATE);
STP_ADD_WEEK_DT;
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'END', SYSDATE);
COMMIT;
PROC_NAME := 'STP_ADD_WEEK_VAR';
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'START', SYSDATE);
STP_ADD_WEEK_VAR;
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'END', SYSDATE);
COMMIT;
PROC_NAME := 'STP_ADD_TEN_DT';
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'START', SYSDATE);
STP_ADD_TEN_DT;
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'END', SYSDATE);
COMMIT;
PROC_NAME := 'STP_ADD_TEN_VAR';
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'START', SYSDATE);
STP_ADD_TEN_VAR;
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'END', SYSDATE);
COMMIT;
PROC_NAME := 'STP_ADD_MON_DT';
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'START', SYSDATE);
STP_ADD_MON_DT;
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'END', SYSDATE);
COMMIT;
PROC_NAME := 'STP_ADD_MON_VAR';
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'START', SYSDATE);
COMMIT;
STP_ADD_MON_VAR;
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'END', SYSDATE);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ERRMSG := SUBSTR(SQLERRM, 1, 100);
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, ERRMSG, SYSDATE);
END ADD_ALL_PART;
PROCEDURE DEL_ALL_PART AS
PROC_NAME VARCHAR2(100);
ERRMSG VARCHAR2(100);
BEGIN
PROC_NAME := 'STP_DEL_DAY';
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'START', SYSDATE);
COMMIT;
STP_DEL_DAY;
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'END', SYSDATE);
COMMIT;
PROC_NAME := 'STP_DEL_TEN';
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'START', SYSDATE);
COMMIT;
STP_DEL_TEN;
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'END', SYSDATE);
COMMIT;
PROC_NAME := 'STP_DEL_WEEK';
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'START', SYSDATE);
COMMIT;
STP_DEL_WEEK;
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'END', SYSDATE);
COMMIT;
PROC_NAME := 'STP_DEL_MON';
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'START', SYSDATE);
COMMIT;
STP_DEL_MON;
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, 'END', SYSDATE);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ERRMSG := SUBSTR(SQLERRM, 1, 100);
INSERT INTO TBL_PART_ERR VALUES (PROC_NAME, ERRMSG, SYSDATE);
END DEL_ALL_PART;
end PKG_MAINTEN_PART;
create or replace procedure dbamon.config_tab_policy(
v_MSG OUT VARCHAR2, ---------信息反馈。
v_table_owner in varchar2, ------分区表属主
v_table_name in varchar2, ------分区表名字
v_drop_time_units in number, ----保留分区个数
v_policy in number, ------1 加删,2不加不删,3,只加不删,4 只删不加。
v_start_time in number default 0, -----开始维护时间(24小时制,0-23)
v_end_time in number default 24, ----结束维护时间 (24小时制,1-24)
v_partition_type in varchar2 default null, ----分区类型,支持WEEK,MONTH,DAY,FIVE,TEN
v_tab_tbs IN VARCHAR2 DEFAULT NULL, -----表所在表空间,可以为空
v_INX_TBS IN VARCHAR2 DEFAULT NULL ------索引所在表空间,可以为空,
) as
l_count number;
l_table_owner varchar2(40);
l_table_name varchar2(40);
l_partition_column_type varchar2(30);
l_partition_type varchar2(100);
l_format varchar2(20);
l_maxpartition varchar2(100);
l_gl_idx number(3);
l_auto varchar2(30);
l_add_time_units number(5);
apperr exception;
begin
l_table_owner := upper(v_TABLE_OWNER);
l_table_name := upper(v_TABLE_NAME);
-----判断输入是否符合规范
--判断是否RANGE分区表
select count(*)
into l_count
from dba_part_tables t
where t.owner = l_table_owner
and t.table_name = l_table_name
and partitioning_type = 'RANGE';
v_msg:='OK';
if l_count = 0 then
v_MSG := '配置失败:表不是分区表或者不是RANGE类型分区';
raise apperr;
end if;
if v_start_time not in (0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23) or
v_end_time not in (1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24) then
v_msg := '配置失败:开始时间应该为0-23之间的整数, 结束时间应该为1-24之间整数';
raise apperr;
end if;
if v_policy not in (1, 2, 3, 4) then
v_msg := '配置失败:policy 参数只能为1,2,3,4, 1 加删,2不加不删,3,只加不删,4 只删不加';
raise apperr;
end if;
if upper(v_partition_type) not in ('WEEK', 'DAY', 'TEN', 'MONTH', 'FIVE') and
v_partition_type is not null then
v_msg := '配置失败, 分区类型只可以为WEEK,DAY,TEN,MONTH,FIVE';
raise apperr;
end if;
---开始收集信息
dbamon.pkg_mainten_part.gather_table_info(l_table_owner, l_table_name);
select count(*)
into l_count
from dbamon.tbl_part_info
where table_owner = v_table_owner
and table_name = v_table_name;
if l_count = 0 then
v_msg := '配置失败:无法获取分区表信息,联系DBA';
raise apperr;
end if;
select partition_column_type,
partition_type,
format,
autointerval,
max_partition,
global_indx
into l_partition_column_type,
l_partition_type,
l_format,
l_auto,
l_maxpartition,
l_gl_idx
from dbamon.tbl_part_info
where table_owner = v_table_owner
and table_name = v_table_name;
if l_partition_column_type like 'TIMESTAMP%' then
l_partition_column_type := 'DATE';
elsif l_partition_column_type in ('CHAR', 'VARCHAR') then
l_partition_column_type := 'VARCHAR2';
end if;
if l_partition_column_type not in ('DATE', 'TIMESTAMP', 'VARCHAR2') then
v_msg := '配置失败: 分区列数据类型只可以为DATE,TIMESTAMP,VARCHAR2,CHAR,VARCHAR 类型';
raise apperr;
end if;
if upper(v_partition_type) in ('WEEK', 'DAY', 'TEN', 'MONTH', 'FIVE') then
l_partition_type := upper(v_partition_type);
end if;
if l_partition_type = 'WEEK' then
l_add_time_units := 12;
elsif l_partition_type = 'MONTH' then
l_add_time_units := 3;
elsif l_partition_type = 'DAY' then
l_add_time_units := 16;
elsif l_partition_type in ('FIVE', 'TEN') then
l_add_time_units := 10;
end if;
if l_auto is not null and v_policy in (1, 3) then
v_msg := '配置失败: 11g 自增长分区,不可以配置成1 加删,3,只加不删';
raise apperr;
end if;
delete dbamon.tbl_tab_part_config
where table_owner = l_table_owner
and table_name = l_table_name;
insert into dbamon.tbl_tab_part_config
(id,
table_owner,
table_name,
partition_column_type,
partition_pre,
partition_type,
drop_time_units,
add_time_units,
tablespace_name,
index_tb_name,
valid_flg,
config_type,
format,
shour,
ehour)
values
(dbamon.SEQ_TM_PART_MAINTEN.NEXTVAL,
l_table_owner,
l_table_name,
l_partition_column_type,
NVL(SUBSTR(l_maxpartition, 1, INSTR(l_maxpartition, '2') - 1), 'PART'),
l_partition_type,
v_drop_time_units,
l_add_time_units,
v_tab_tbs,
v_INX_TBS,
v_policy,
'RUN',
l_format,
v_start_time,
v_end_time);
insert into dbamon.tbl_config_log
(config_time,
username,
oseruser,
proxy_user,
ip_addr,
machine,
table_owner,
table_name,
drop_time_units,
policy,
v_start_time,
v_end_time,
v_partition_type,
v_tab_tbs,
v_inx_tbs,
config_result)
values
(sysdate,
SYS_CONTEXT('USERENV', 'CURRENT_USER'),
SYS_CONTEXT('USERENV', 'OS_USER'),
SYS_CONTEXT('USERENV', 'PROXY_USER'),
SYS_CONTEXT('USERENV', 'IP_ADDRESS'),
SYS_CONTEXT('USERENV', 'TERMINAL') ,
v_table_owner,
v_table_name,
v_drop_time_units,
v_policy,
v_start_time,
v_end_time,
v_partition_type,
v_tab_tbs,
v_inx_tbs,
v_msg);
commit;
exception
when apperr then
dbms_output.put_line(v_msg);
insert into dbamon.tbl_config_log
(config_time,
username,
oseruser,
proxy_user,
ip_addr,
machine,
table_owner,
table_name,
drop_time_units,
policy,
v_start_time,
v_end_time,
v_partition_type,
v_tab_tbs,
v_inx_tbs,
config_result)
values
(sysdate,
SYS_CONTEXT('USERENV', 'CURRENT_USER'),
SYS_CONTEXT('USERENV', 'OS_USER'),
SYS_CONTEXT('USERENV', 'PROXY_USER'),
SYS_CONTEXT('USERENV', 'IP_ADDRESS'),
SYS_CONTEXT('USERENV', 'TERMINAL') ,
v_table_owner,
v_table_name,
v_drop_time_units,
v_policy,
v_start_time,
v_end_time,
v_partition_type,
v_tab_tbs,
v_inx_tbs,
v_msg);
commit;
when others then
v_msg := substr(sqlerrm, 1, 50);
insert into dbamon.tbl_config_log
(config_time,
username,
oseruser,
proxy_user,
ip_addr,
machine,
table_owner,
table_name,
drop_time_units,
policy,
v_start_time,
v_end_time,
v_partition_type,
v_tab_tbs,
v_inx_tbs,
config_result)
values
(sysdate,
SYS_CONTEXT('USERENV', 'CURRENT_USER'),
SYS_CONTEXT('USERENV', 'OS_USER'),
SYS_CONTEXT('USERENV', 'PROXY_USER'),
SYS_CONTEXT('USERENV', 'IP_ADDRESS'),
SYS_CONTEXT('USERENV', 'TERMINAL') ,
v_table_owner,
v_table_name,
v_drop_time_units,
v_policy,
v_start_time,
v_end_time,
v_partition_type,
v_tab_tbs,
v_inx_tbs,
v_msg);
commit;
end;
grant select on DBAMON.TBL_PART_INFO to bspdev;
grant select on DBAMON.TBL_PART_INFO to PUBLIC;
grant select on DBAMON.TBL_TAB_PART_CONFIG to bspdev;
grant select on DBAMON.TBL_PART_MANAGE_SQL to PUBLIC;
grant select on DBAMON.TBL_PART_MANAGE_SQL to bspdev;
grant select on DBAMON.TBL_PART_MANAGE_SQL to PUBLIC;
grant select on DBAMON.TBL_PART_ERR to PUBLIC;
grant select on DBAMON.TBL_PART_ERR to bspdev;
grant select on DBAMON.TBL_CONFIG_LOG to PUBLIC;
grant select on DBAMON.TBL_CONFIG_LOG to bspdev;
grant execute on DBAMON.config_tab_policy TO PUBLIC;
grant select_catalog_role to dbamon;
--dbmon
declare
v_job number;
begin
sys.dbms_job.submit(
job => v_job,
what=> 'pkg_mainten_part.ADD_ALL_PART();
pkg_mainten_part.del_ALL_PART();',
next_date=>sysdate,
interval =>'sysdate+1/24');
commit;
end;