1、概述
1.1、关于工作流数据
提到工作流数据,就不得不提业务数据。作为最直接的区分,我们将存储于业务系统中的数据称为业务数据,将存储于工作流系统中的数据称为工作流数据。根据 WFMC 定义,我们将工作流数据分为工作流控制数据和工作流相关数据。
1、 工作流控制数据 。指被工作流系统管理的系统数据,这些数据包括了与流程实例和任务实例相关的执行数据,例如流程实例的状态、执行时间等信息、任务实例的执行者、执行时间、状态、紧急程度等。
2、 工作流相关数据 。指与业务流程相关的数据。工作流相关数据又具体分为 3 种:
- 影响流程实例执行的业务数据。在 WFMC 中, 这个数据被描述为:工作流系统通过该数据来确定流程实例的流转条件,并选择下一个将执行的任务,这些数据可以被业务系统访问并修改。例如报销流程中的“报 销金额”,这个数据会决定该流程的审批路径;再例如为任务设置的超时时间,这个数据会触发任务的取消。实质上这些数据就是工作流系统需要依赖于进行流程流 转的业务数据。
- 契合业务的关联数据。指工作流系统与业务系统进行关联的数据,例如特定于 WEB 系统,工作流系统会在每个流程实例里保持有导航至对应业务表单的 URL 。
- 传递作用的业务数据。当流程跨越多个业务模块时,需要在模块间传递数据,此时会利用工作流系统进行传递,会在工作流系统里暂时存储这些业务数据。
1.2、关于基于Cordys平台的办公系统
办公系统是基于SOA和BPM技术架构,采用Cordys平台建设的信息系统,实现了办公业务集中化、全面化管理,初步达到集中办公平台的目的,系统主要包括公文管理、通用办公、专业流程、综合信息、专业办公五大子系统。
在此工作流数据有哪些应用场景呢?
- 首先,在系统建设时,为了快速开发,系统设计时,工作流数据与业务数据耦合较多,也就是说工作流数据与业务系统集成在一起,虽然如此,但是很多数据在流程结束后,是可以剥离。
- 其次,虽然很多工作流产品都提供了办结流程数据解决方案,例如按时间迁移清理历史数据。而在实际业务系统建设、使用过程中,个性化需求驱动下,产品所提供的功能往往失效,例如:例如主流程下涵盖子流程,在子流程结束时,而主流程可能没有结束,而从流程实例角度来说,某个子流程已经结束。
办公系统已经上线使用4年多了,其中某流程处理数据表(process_activity)的记录已经有5千多万条,其中在两年前处理过,并迁移走近2千万条,实践证明此处理方案有效,对业务影响可以忽略,特殊情况人工处理就可以。
2、Cordys工作流相关主要表及解决方案
2.1、Cordys核心表及相关业务表
如上图所示,表的情况如下:
序号 |
表名 |
功能介绍 |
1 |
Process_instance |
流程实例 |
2 |
process_activity |
流程实例处理活动 |
3 |
MESSAGE_TRACK |
流程实例处理消息活动 |
4 |
MESSAGE |
流程实例处理消息 |
5 |
NOTIFICTION_SEARCH_DATA |
|
6 |
TASK_LIST |
待办任务处理活动(业务) |
7 |
WORKFLOW_INSTANCE_TRANSLOG |
流程流转记录(业务) |
8 |
PROCESS_INSTANCE_DATA |
在途流程实例(未办结流程实例) |
上表中,Cordys流程核心表有Process_instance、process_activity、MESSAGE_TRACK、MESSAGE、NOTIFICTION_SEARCH_DATA、PROCESS_INSTANCE_DATA,其中PROCESS_INSTANCE_DATA是在途流程信息,不需要清理,其他的需要适当的情况,而业务表的TASK_LIST中数据,办结流程的任务迁移到task_list_finished表中,表结构完全一致。
2.2、清理迁移数据解决方案
流程办结数据与在途数据,经过对比分析,最多记录表process_activity表的在途记录数也不过百万级别,而办结数据已经3千多万,因此处理方案的基本原理是:
- 现有的待处理的Cordys核心表更名为备份表,保证数据不丢失;
- 重建Cordys待处理核心表,新建表时索引、主键先不建,等数据处理后再建;
- 依据未办结业务数据的流程实例信息,导数据插入对应的新建的表中;
- 系统恢复运行3~6个月后,根据存储空间情况,自行删除已经成为历史数据的表。
2.2.1、Cordys核心表处理过程
由于PROCESS_INSTANCE_DATA表是在途流程实例,不需要进行处理。
2.2.2、关于办结流程的识别
办结流程可以根据ApptoolKit中workflow_instance表来识别(例如:STATUS = ‘COMPLETE‘),同时,还需要识别其中的子流程,以及嵌套子流程(例如:通过PARENT_GUID和GUID两个字段来进行识别),识别出三级嵌套就足够了,再特殊的,人工处理。
把识别出来的办结流程标识,去重后放置在临时表中,后续使用。
2.2.3、任务表数据清理迁移方案
任务表(task_list)主要是存储在办和办结任务数据,办结任务数据要定期迁移到办结任务表中(task_list_finish)。
2.2.4、存储表空间回收处理方案
由于Cordys核心表用到LOB字段,用于存储XML格式数据,这样将占有大量磁盘空间(按现有业务量估算,3年预计为1T),因此,在删除表的时候,最好也移除表空间。
3、数据迁移清理实践
3.1、数据处理全过程概述
1、策划分析阶段工作
全面获取存储、表空间使用情况,以及相关表数据量,并通过查询等多种模式模拟数据处理过程及所消耗的时间,并据此预估数据处理停业时间,制定作业计划。
导出建表、索引SQL语句(因为系统在运维过程中,可能要发生微小的改变,因此,每次都要重新生产SQL脚本)。
2、发通知,停业,停应用服务
3、表更名、索引更名
4、新建表,处理数据
根据实际情况,如有必要则新建表空间,把表建到新表空间上。
5、重建索引、存储过程、触发器等
按事先准备好的脚本执行。
6、启动应用服务,检查平台
7、测试流程相关应用,并处理问题
8、清理测试数据
9、恢复业务。
3.2、关键过程案例
3.2.1、表更名
--修改表名
alter table notification_search_data rename to bak_notification_search_data;
alter table message_track rename to bak2011_message_track;
alter table message rename to bak2011_message;
alter table process_activity rename to bak2011_process_activity;
alter table process_instance_data rename to bak2011_process_instance_data;
alter table process_instance rename to bak2011_process_instance;
alter table workflow_instance rename to bak2011_workflow_instance;
alter table workflow_instance_translog rename to bak_workflow_instance_translog;
--修改约束
alter table MESSAGE rename constraint MESSAGEPKEY to MESSAGEPKEYtmp;
alter table MESSAGE_TRACK rename constraint MESSAGETRACKPKEY to MESSAGETRACKPKEYtmp;
alter table PROCESS_ACTIVITY rename constraint SYS_C006752 to SYS_C006752tmp;
略
--修改索引
alter index IX_PROCESS_INSTANCE_START_TIME rename to IX_PROCESS_INSTANCE_STARTtmp;
alter index IX_PROCESS_NAME rename to IX_PROCESS_NAMEtmp;
alter index IX_PROCESS_INSTANCE_END_TIME rename to IX_PROCESS_INSTANCE_END_Ttmp;
alter index SYS_C006752 rename to SYS_C006752tmp;
3.2.2、处理工作流数据
使用存储过程处理数据,最少分成两个阶段,第一阶段处理流程实例数据,根据处理结果,提取流程消息数据,再进行第二阶段流程消息数据处理,由于插入数据时,表不适宜建索引,所以在process_activity数据处理完成后,为此表建主键、索引,才方便提取消息message_id。
select distinct t.message_id
from cordys.process_activity t
where not exists (select t1.message_id from cordys.message t1 where t1.message_id = t.message_id);
1、处理流程实例数据
create or replace procedure pro_data_new1 is
--游标,取出待处理的办结流程guid
cursor wait_worklow_instance is
select t.workflow_instance, t.process_instance from wait_worklow_instance_temp t where t.process_instance is not null
and not exists (select t1.guid from cordys.workflow_instance t1 where t1.guid = t.workflow_instance);
v_instance_count number(9);
v_num number(9); --提交计数
v_sqlcode number;
v_sqlmsg varchar2(2000);
v_instance_guid cordys.workflow_instance.guid%type;
v_process_instance cordys.workflow_instance.process_instance%type;
v_log_id number;
begin
v_instance_count := 0;
v_num := 0;
v_log_id := 0;
select count(*) into v_log_id from tmp_workflow_data_log;
if v_log_id > 0 then
select max(id) into v_log_id from tmp_workflow_data_log;
end if;
v_log_id := v_log_id + 1;
insert into tmp_workflow_data_log(id,state,logdate) values(v_log_id,‘Start Test!‘,sysdate);
open wait_worklow_instance;
loop
fetch wait_worklow_instance into v_instance_guid, v_process_instance;
exit when wait_worklow_instance%notfound;
select count(*)
into v_instance_count from cordys.bak2011_workflow_instance where guid = v_instance_guid;
if v_instance_count > 0 then
--迁移流程实例数据
insert into cordys.process_instance
select * from cordys.bak2011_process_instance where instance_id = v_process_instance;
--迁移流程活动数据
insert into cordys.process_activity
select * from cordys.bak2011_process_activity where instance_id = v_process_instance;
end if;
if v_num > 1000 then
v_log_id := v_log_id + 1;
insert into tmp_workflow_data_log(id,state,logdate) values(v_log_id,‘insert 1001 record workflow‘,sysdate);
commit;
v_num := 0;
else
v_num := v_num + 1;
end if;
end loop;
v_log_id := v_log_id + 1;
insert into tmp_workflow_data_log(id,state,logdate) values(v_log_id,‘insert workflow data complete‘,sysdate);
commit;
close wait_worklow_instance;
commit;
exception
when others then
v_sqlcode := sqlcode;
v_sqlmsg := substr(sqlerrm, 1, 2000);
dbms_output.put_line(v_sqlcode || ‘::‘ || v_sqlmsg);
end;
--其中,每千条数据提交一次,为了是数据处理稳定,并根据日志监控进程。
2、处理流程消息数据
create or replace procedure pro_data_new2 is
--注意:process_instance流程实例为空的滤除
cursor tmp_message is
select distinct t.message_id from cordys.tmp_message_id_201112 t
where not exists (select t1.message_id from cordys.message t1 where t1.message_id = t.message_id);
v_instance_count number(9);
v_num number(9); --提交计数
v_sqlcode number;
v_sqlmsg varchar2(2000);
v_instance_guid cordys.workflow_instance.guid%type;
v_process_instance cordys.workflow_instance.process_instance%type;
v_message_id cordys.message.message_id%type;
v_log_id number;
begin
v_instance_count := 0;
v_num := 0;
v_log_id := 0;
select count(*) into v_log_id from tmp_workflow_data_log;
if v_log_id > 0 then
select max(id) into v_log_id from tmp_workflow_data_log;
end if;
v_log_id := v_log_id + 1;
insert into tmp_workflow_data_log(id,state,logdate) values(v_log_id,‘Start Test!‘,sysdate);
v_num := 0;
open tmp_message;
loop
fetch tmp_message
into v_message_id;
exit when tmp_message%notfound;
--迁移消息数据表
insert into cordys.message select * from cordys.bak2011_message where message_id = v_message_id;
--迁移消息跟踪数据表
insert into cordys.message_track
select * from cordys.bak2011_message_track where message_id = v_message_id;
--迁移消息通知数据表
insert into cordys.notification_search_data
select * from cordys.bak_notification_search_data where message_id = v_message_id;
if v_num > 1000 then
v_log_id := v_log_id + 1;
insert into tmp_workflow_data_log(id,state,logdate) values(v_log_id,‘insert 1001 record message‘,sysdate);
commit;
v_num := 0;
else
v_num := v_num + 1;
end if;
end loop;
close tmp_message;
v_log_id := v_log_id + 1;
insert into tmp_workflow_data_log(id,state,logdate)
values(v_log_id,‘insert message data complete‘,sysdate);
commit;
exception
when others then
v_sqlcode := sqlcode;
v_sqlmsg := substr(sqlerrm, 1, 2000);
dbms_output.put_line(v_sqlcode || ‘::‘ || v_sqlmsg);
end;
3.3、其它注意事项
1、手工恢复触发器
触发器、Sequence是最容易忽略、出问题的地方,因为在表更名时,对应的代码可能发生改变,一定要注意核对。
AFTER_INSERT_MESSAGE_TRACK
AFTER_UPDATE_MESSAGE_TRACK
AFTER_UPDATE_PROCESS_INSTANCE
2、异常数据永远是存在的,只能人工分析进行处理,如果一个流程跑3个月了,是因为异常数据,估计这个流程实例也就是个作废的流程实例。
4、总结
本文所描述的历史数据处理方案、思想可以推广到其他系统,而处理数据如此麻烦,也和最初设计有不合理的地方有关,设计人员可以从中汲取些经验教训,有遗漏、不完善的后续完善。
欢迎同行多交流。
参考:
ronghao100 ,浅谈工作流数据
, http://blog.csdn.net/ronghao100/article/details/5625120
Oracle中查询索引名称,批量修改索引名称语句 , http://blog.csdn.net/xiaoyw71/article/details/15338405
关于Cordys平台办结流程数据管理方案 , http://blog.csdn.net/xiaoyw71/article/details/15338391
基于Cordys平台上的待办任务优化改造方案 , http://blog.csdn.net/xiaoyw71/article/details/15338373