背景:

数据库的表数据太多会影响系统整体的性能,而数据在清理之前,需要备份到其他地方(CSV, 其他表), 以免不时之需,比如审计。

花了2到3个小时写的,太久没写了,测试花了蛮多时间,希望能够给有类似需求的人带来帮助。

这个存储过程核心是根据数据库表结构定义,构建出merge into语句:

 1 /**
 2  * Common procedure to merge TABLE_X to ARCH_TABLE_X.
 3  * The main logic is to build a common merge into statement for tables with different column
 4  * You many need change the target table prefix from 'ARCH' to the one you want in this procedure. 
 5  * Author 烂人
 6  * @tbl_name is the source data table
 7  * @unique_key is the key to uniquely identify a data row
 8  * @days_to_keep days to keep in original table, which means the rest data which plans to delete need merge into archiving table
 9  */
10 create or replace PROCEDURE "PRC_ARCH_TABLE" 
11   (tbl_name VARCHAR2, unique_key VARCHAR2, days_to_keep Integer)
12 IS
13   v_columns_1 VARCHAR2 (4000);
14   v_columns_2 VARCHAR2 (4000);
15   v_columns_3 VARCHAR2 (4000);
16   v_columns_4 VARCHAR2 (4000);
17   v_stmt VARCHAR2 (8500);
18 BEGIN
19   --SET days_to_keep := days_to_keep - 1;
20   -- bulk fetch the column of selected table
21   select 
22   rtrim(xmlagg(xmlparse(content column_name || ',' wellformed) ORDER BY t.column_name).getclobval(), ','),
23   rtrim(xmlagg(xmlparse(content 'x.'|| column_name || ',' wellformed) ORDER BY t.column_name).getclobval(), ','),
24   rtrim(xmlagg(xmlparse(content 'y.'|| column_name || ',' wellformed) ORDER BY t.column_name).getclobval(), ',')
25   into v_columns_1, v_columns_2, v_columns_3
26   from all_tab_cols t where table_name = tbl_name and hidden_column = 'NO' GROUP BY table_name;
27  
28   select 
29    rtrim(xmlagg(xmlparse(content 'x.'|| column_name || '=' || 'y.' || column_name || ',' wellformed) ORDER BY t.column_name).getclobval(), ',')
30   into v_columns_4
31   from all_tab_cols t where table_name = tbl_name and hidden_column = 'NO' and column_name <> upper(unique_key) GROUP BY table_name;
32 
33   v_stmt := 'MERGE INTO ARCH_'
34       || tbl_name 
35       ||' x USING (SELECT ' 
36       || v_columns_1 
37       || ' FROM '
38       || tbl_name
39       || ' WHERE CREATE_DATE <= current_date - NUMTODSINTERVAL(' || (days_to_keep-1) || ', ''day'')) y ON (x.'
40       || unique_key
41       || '=y.'
42       || unique_key
43       || ')WHEN MATCHED THEN UPDATE SET '
44       || v_columns_4
45       || ' WHEN NOT MATCHED THEN INSERT ('
46       || v_columns_2
47       || ') values ('
48       || v_columns_3
49       || ')';
50       --DBMS_OUTPUT.PUT_LINE(v_stmt); 
51       EXECUTE IMMEDIATE v_stmt;
52       DBMS_OUTPUT.PUT_LINE('Successfully execute ' || v_stmt); 
53     EXCEPTION
54       WHEN OTHERS THEN
55         DBMS_OUTPUT.PUT_LINE('Failed to execute: ' || v_stmt); 
56         DBMS_OUTPUT.PUT_LINE('Error msg: ' || sqlerrm); 
57 END;

当然,用于备份的表数据不能无限增长,根据业务需要,可以把过时的数据清理掉,比如审计一般要保留3到5年,平常报文日志表只要保留1个月。

这个是清理旧数据的代码,清除的配置在CONFIGURATION表中,可以自己建一个,关键是要有data_key和value两个字段和下面的Procedure匹配:

 1 create or replace PROCEDURE  "PRC_ARCH_DATA_CLEAN" 
 2   (tbl_name VARCHAR2)
 3 IS
 4   v_stmt VARCHAR2 (4000);
 5   keep_month INTEGER;
 6 BEGIN
 7   SELECT NVL(SUM(TO_NUMBER(value)), 0) INTO keep_month FROM CONFIGURATION WHERE data_key=upper(tbl_name);
 8   IF  keep_month = '0' THEN
 9     DBMS_OUTPUT.PUT_LINE('The archiving table did not configured correctly!');
10   ELSE
11     v_stmt := 'DELETE FROM '
12       || tbl_name 
13       || ' WHERE CREATE_DATE < current_date - numtoyminterval('||keep_month||',''month'')';
14       EXECUTE IMMEDIATE v_stmt;
15       DBMS_OUTPUT.PUT_LINE('Successfully execute ' || v_stmt); 
16   END IF;
17  EXCEPTION
18   WHEN OTHERS THEN
19     DBMS_OUTPUT.PUT_LINE('Failed to execute: ' || v_stmt); 
20     DBMS_OUTPUT.PUT_LINE('Error msg: ' || sqlerrm);
21 END;

 

posted on 2023-11-29 11:52  烂人  阅读(10)  评论(0编辑  收藏  举报