起原:网海拾贝
Oracle数据库里存放着林林总总的数据,个中有一些数据表会随着时辰的推移,越来越除夜。如交友谈天的日志、短信收发的日志、消费琐细的日志、静态网站发布琐细的日志等等。何等的信息又和时辰精密相关,有没有装备让这些日志表能按时辰自动瓜分红汗青年月(如log200308,log200309)的表呢? 请看看我用存储进程活期瓜分表的门径吧。
一、标题问题的引出
1.初学数据库时只晓得用delete来删除表里的数据。但在Oracle数据库里,除夜量delete记录后,并不克不及释放表所占用的物理空间,这里面有一个高水位的看法,以是我们不克不及用delete来瓜分表。
2.用重定名(rename)表的门径
(1) 先建一个和原昔日志表(倘使是log)数据组织如出一辙的新表(如log_new),建约束、索引及指定字段的默许值;
(2) 重定名表log到log_YYYYMM;
要过细的标题问题是OLTP琐细能够会因为DML把持窒碍重定名实行告成,出现ORA-00054本钱正忙的错误提示,需求试频频才干告成。
(3) 重定名表log_new到log。
何等应用挨次不消编削(受影响的时辰仅几秒钟),日志表就被截断瓜分了。
上述步骤可以在Oracle里用存储进程来完成。
二、用存储进程来瓜分表
可以看到在重定名表的门径中,步骤(2)是个关键。上面这个rename_table进程会在有锁窒碍的情形下用递归的体例重试100次。
重定名原始表到目标表的存储进程rename_table:
create or replace procedure rename_table (source_name in varchar2, target_name in varchar2, times in out number) is query_str varchar2(4000); source_name1 varchar2(64); target_name1 varchar2(64); cursor c1 is select segment_name from user_segments where segment_name=upper(source_name); dummy c1%rowtype; cursor c2 is select segment_name from user_segments where segment_name=upper(target_name); dummy2 c2%rowtype; begin source_name1:=source_name; target_name1:=target_name; open c1; fetch c1 into dummy; -- if c1%found then -- dbms_output.put_line(source_name1||'exist!'); -- end if; open c2; fetch c2 into dummy2; -- if c2%notfound then -- dbms_output.put_line(target_name1||'not exist!'); -- end if; if c2%notfound and c1%found then query_str :='alter table '||source_name1||' rename to ' ||target_name1; execute immediate query_str; dbms_output.put_line('rename success!'); end if; close c1; close c2; exception WHEN OTHERS THEN times:=times 1; if times<100 then -- dbms_output.put_line('times:'||times); rename_table(source_name1,target_name1,times); else dbms_output.put_line(SQLERRM); dbms_output.put_line('error over 100 times,exit'); end if; end; / 截断瓜分log表的存储进程log_history: create or replace procedure log_history is query_str varchar2(32767); year_month varchar2(8); times number; begin select to_char(sysdate-15,'YYYYMMDD') into year_month from dual; times:=0; query_str :='create table log_new pctfree 10 pctused 80 as select * from log where 1=2'; execute immediate query_str; query_str :='alter table log_new add constraints log_' ||year_month||'_pk primary key (id) tablespace indx nologging pctfree 10'; execute immediate query_str; query_str :='alter table log_his modify logtime default sysdate'; execute immediate query_str; query_str :='create index log_'||year_month||'_logtime on log(logtime) tablespace indx nologging pctfree 10'; execute immediate query_str; rename_table('log','log'||year_month,times); query_str :='alter table log_new rename to log'; execute immediate query_str; end; /
虽然您使命情形的日志表能够和我这个做例子的日志表组织上有所分比方,约束前提、索引和默许值都不尽不异。只需稍加编削就可以了。
三、用户需求有create any table琐细权限(不是角色里网罗的权限)
因为在实行存储进程时,由角色授予的权限会失效, 以是实行log_history的用户必定要有DBA独自授予的create any table琐细权限。
最后在OS里按时每月一号平明0:00分实行log_history,让存储进程活期瓜分表。
倘使要瓜分的日志表许多,模仿log_history可以写许多类似的存储进程来瓜分分比方项目里的日志表。然后让OS按月,按周除夜概不活期的实行这些存储进程, 治理员只需查抄日志就可以了。
四、其它过细事变
倘使应用挨次有BUG,能够对在用原始日志表孕育产生历久不克不及释放的锁,实行log_history重定名会不告成。
这时DBA可以查抄数据字典:
select object_id,session_id,locked_mode from v$locked_object; select t2.username,t2.sid,t2.serial#,t2.logon_time from v$locked_object t1,v$session t2 where t1.session_id=t2.sid order by t2.logon_time;
如果有历久出现的如出一辙的列(网罗登录时辰),能够是没有释放的锁。
我们要在实行瓜分日志表的存储进程前,用上面SQL语句杀失历久没有释放非正常的锁:
alter system kill session 'sid,serial#';
五、终了语
用上面介绍的存储进程活期瓜分日志表有很除夜的灵动性。汗青数据不光盘考便当,转移和备份起来也都很容易。Unix和Windows平台的都可以应用。对效劳器硬盘空间较小的中小型公司意义尤其明显。
版权声明: 原创作品,承诺转载,转载时请务必以超链接方式标明文章 原始出处 、作者信息和本声明。不然将清查法律责任。