国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數據庫 > Oracle > 正文

在ORACLE里用存儲過程定期分割表

2024-08-29 13:29:19
字體:
來源:轉載
供稿:網友

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_nameinvarchar2,target_namein varchar2,timesin outnumber) isquery_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; beginsource_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 thenquery_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;exceptionwhen others then times:=times+1;if times<100 then-- dbms_output.put_line('times:'||times);rename_table(source_name1,target_name1,times);elsedbms_output.put_line(sqlerrm);dbms_output.put_line('error over 100 times,exit');end if;end;/截斷分割log表的存儲過程log_history:create or replace procedure log_historyisquery_str varchar2(32767);year_month varchar2(8);timesnumber;beginselect to_char(sysdate-15,'yyyymmdd') into year_month from dual;times:=0;query_str :='create table log_new pctfree 10 pctused 80as select * from log where 1=2';execute immediate query_str;query_str :='alter table log_new add constraints log_' ||year_month||'_pkprimary 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平臺的都可以使用。對服務器硬盤空間較小的中小型公司意義尤其明顯。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 黑龙江省| 汉川市| 宁南县| 白水县| 台东市| 诸城市| 广丰县| 西青区| 临泉县| 会宁县| 兴义市| 宜君县| 尖扎县| 饶阳县| 上虞市| 孝义市| 渭源县| 太原市| 海盐县| 南昌县| 佛山市| 揭西县| 垫江县| 黔江区| 都匀市| 邹平县| 祁东县| 甘孜县| 台江县| 广西| 马关县| 金门县| 闻喜县| 三亚市| 澄城县| 江陵县| 阿图什市| 高碑店市| 宿州市| 城市| 正安县|