Flowable工作流历史表数据越来越大,影响运行效率,该如何提升性能?
Flowable 历史表越来越大时,真正有效的办法不是先加一条索引,也不是直接执行 DELETE。企业需要同时控制历史数据的生成量、修正查询方式、建立分级保留周期,并通过 Flowable 官方历史清理能力小批量回收数据;索引、统计信息和数据库维护则应以慢 SQL 与执行计划为依据。
还要先澄清一个常见误区:历史表变大,并不意味着每一次流程流转都会直接扫描历史表。Flowable 把运行时数据与历史数据分开管理,但历史写入仍会占用数据库事务、日志、缓存和 I/O;历史查询、报表统计以及大批量删除,也会与运行时审批争夺数据库资源。因此,性能治理要从“运行链路是否被历史负载拖累”入手,而不是只看表行数。
本文以 Flowable 8.0.0 为主要版本边界,结合官方历史文档、Housekeeping 文档、建表脚本和清理作业源码,给出一套适合企业私有化部署的治理方案。
一、核心结论与问题边界
先给答案:用五层方案治理,而不是只做一次删库
一套可持续的方案包含五层:第一层减少不必要的历史明细;第二层把在线查询改成有边界、有索引、可分页的查询;第三层按流程类型建立保留策略;第四层使用官方批处理能力归档和清理;第五层持续观察容量、慢 SQL、数据库日志和清理积压。

如果只能先做三件事,建议依次完成:统计各历史表和索引的增长速度;定位真正影响审批链路的 SQL 与数据库等待;选一个低风险流程,在非高峰期按小批次试运行历史清理。没有度量和回滚方案的“大扫除”,很容易把容量问题变成锁等待、日志暴涨或复制延迟。
Flowable 历史表分别保存什么
历史数据不是一张表。流程实例、活动轨迹、人工任务、变量、变量变更、候选关系、批注和附件分别落在不同的历史表中,增长规律也不同。
| 典型表 | 主要内容 | 常见增长原因 | 优先关注指标 |
|---|---|---|---|
| ACT_HI_PROCINST | 历史流程实例 | 实例总量持续累积 | 完成时间、流程定义、租户 |
| ACT_HI_ACTINST | 节点活动轨迹 | 节点多、循环和回退频繁 | 单实例活动数、时间范围 |
| ACT_HI_TASKINST | 历史人工任务 | 会签、加签、转办产生更多任务 | 办理人、结束时间、实例 |
| ACT_HI_VARINST | 历史变量当前值 | 变量多、对象大、频繁更新 | 变量名、实例、字节数据 |
| ACT_HI_DETAIL | 变量更新与表单明细 | full 历史级别记录更新细节 |
行数、时间、变量名 |
| ACT_HI_IDENTITYLINK | 历史候选人与候选组 | 候选范围大、多人审批 | 任务、流程实例 |
| ACT_HI_COMMENT / ATTACHMENT | 意见和附件元数据 | 审批意见多、附件多 | 实例、任务、内容大小 |
Flowable 8.0.0 的 MySQL 历史建表脚本已经为完成时间、业务主键、流程实例关联、活动时间、变量实例关联等通用路径建立基础索引。这些索引是通用起点,不等于覆盖了企业自己的组合查询;也不应因为“表大”就机械地重复建同类索引。
为什么历史表会间接拖慢正在运行的流程

第一条链路是写放大。流程流转除了更新运行时状态,还可能插入或更新历史活动、任务、变量和明细。历史级别越高、变量更新越频繁,同一次业务事务涉及的写入越多。
第二条链路是共享数据库资源。历史写入、在线查询和清理都会消耗事务日志、缓存、磁盘 I/O、检查点或后台维护能力。具体表现因 MySQL、PostgreSQL、Oracle 等数据库而异,但结论一致:必须用数据库指标证明瓶颈,不能仅凭表行数推断。
第三条链路是查询失控。管理端常见的“全量已办数量”“跨多年流程检索”“附带全部变量的分页”可能触发大范围扫描、回表和排序。它们通常比引擎自身的运行时查询更容易成为性能热点。
第四条链路是删除冲击。一次删除数百万行,会产生大量事务日志和索引维护,还可能拉长锁持有时间。历史数据该清理,但必须把删除压力切成数据库能消化的小批次。
二、关键概念与能力差异
第一步不是优化,而是建立容量与慢 SQL 基线
至少连续观察一个完整业务周期,并回答以下问题:哪张历史表增长最快;数据行和索引各占多大空间;每完成一个典型流程会新增多少历史记录;最慢 SQL 来自审批流转、已办查询、报表还是清理;数据库等待集中在 CPU、I/O、锁、日志还是网络。
建议形成一张每周容量表:表行数、表大小、索引大小、日增量、预计耗尽时间、最长查询、P95 写入时延和失败清理批次数。对高峰与低峰分别采样,因为低峰期跑得快的清理任务,可能在月末审批高峰造成完全不同的影响。
诊断时要把运行时 API、历史查询 API、自定义报表 SQL 和数据库后台任务分开标记。只有知道负载来自哪里,后续的历史级别、索引或归档措施才有针对性。
历史级别决定了数据生成的上限
Flowable 官方文档提供 none、activity、audit 和 full 四档历史级别。选择标准不是“越完整越好”,而是审计义务和排障需要。
| 历史级别 | 保留范围概括 | 性能与容量 | 适用边界 |
|---|---|---|---|
| none | 不保存历史 | 运行开销最低 | 极少数无审计要求场景 |
| activity | 流程实例和活动轨迹为主 | 数据较少 | 只要求基本轨迹 |
| audit | 活动、任务、变量等审计信息 | 官方默认,平衡性较好 | 大多数企业审批 |
| full | 在 audit 基础上保留更多明细,尤其变量更新 | 数据最多、写入最重 | 确有变量变更审计要求 |
不要为了调试方便,让所有生产流程永久使用 full。可以按环境和业务合规要求确定级别,并用日志、业务审计表或可观测平台承担不必进入流程历史库的技术诊断信息。更改历史级别只影响后续生成方式,已有历史数据仍需另行治理。
三、模型架构与运行机制
Flowable 7 和 8 不应再套用“开启异步历史”的旧建议
互联网上仍有文章建议通过异步历史把历史写入移出主事务。这个建议有明确版本边界:Flowable 7.0.0 的官方发布说明已经宣布移除异步历史支持,Flowable 8 也不应继续按旧版配置实施。
需要区分两个概念:异步历史持久化已被移除;历史清理仍然由定时作业触发,并通过批处理和异步执行器推进删除任务。前者是历史如何写入,后者是已完成历史如何清理,不能混为一谈。
变量往往是被忽略的容量放大器
大 JSON、序列化对象、表单快照和附件内容不宜在流程变量中反复覆盖。每次更新都可能带来历史记录、字节数组、事务日志和对象反序列化成本,full 级别下尤其明显。
更稳妥的做法是:流程变量只保存路由和审批所需的小字段;大正文、附件和版本化业务数据存入业务库或对象存储;流程中保存稳定引用、摘要和必要快照。对确需审计的关键变量,明确变量白名单、大小上限和更新频率。
清理历史流程实例时,也要验证相关字节数据、意见、附件和扩展引擎数据是否按预期处理。Flowable 开源版的 BPMN/CMMN Housekeeping 不等于自动清理所有外围引擎与业务表。
四、核心场景与处理策略
历史查询要有边界,分页也要避免隐形全表扫描
历史列表至少应带上租户、流程定义范围、完成状态和时间区间中的若干条件。业务主键精确查询与“近三个月我的已办”应走不同查询模型,不能让一个万能检索接口承载所有报表需求。
深分页会不断跳过前面的数据,页码越大成本越高。大数据集导出和后台扫描更适合使用稳定排序键的游标式分页;用户界面则限制最大时间范围、最大翻页深度和单页大小。列表页不要默认加载全部流程变量,也不要每次刷新都做跨多年精确总数统计。
报表需要复杂聚合时,应把历史数据增量同步到分析库或数仓。流程数据库首先服务事务处理,不应同时承担任意维度的探索式分析。
索引必须从真实 SQL 和执行计划反推
组合索引应匹配实际的等值条件、范围条件和排序方式。例如,某租户下按流程定义查询已完成实例,并按结束时间倒序展示,索引设计就要围绕该固定查询形态验证,而不是只给 END_TIME_ 再加一条重复索引。
每增加一个索引都会增加历史写入和删除的维护成本。上线前应在接近生产规模的数据上查看执行计划,确认过滤行数、排序方式、回表量与索引选择;上线后观察写入时延和磁盘增量。无效或高度重叠的索引要经过审批后移除。
数据库还需要按产品特性维护统计信息和表空间。PostgreSQL 要关注 vacuum、膨胀与统计信息;MySQL 要关注 InnoDB 缓存、redo、undo 和长事务;Oracle 要关注统计信息、段空间和归档日志。这里不存在一条跨数据库通用的“最佳维护命令”。
五、数据、规则与状态设计
Flowable 官方 History Cleaning 如何工作
Flowable 的自动历史清理默认关闭。官方文档给出的常用 Spring Boot 配置如下,默认语义是每天凌晨 1 点清理已结束超过 365 天的实例;生产环境应根据合规周期和数据库承载能力调整。
flowable.enable-history-cleaning=true
flowable.history-cleaning-after=365d
flowable.history-cleaning-cycle=0 0 1 * * ?
flowable.history-cleaning-batch-size=100

从 Flowable 8.0.0 源码看,清理管理器构造“结束时间早于保留阈值”的历史流程实例查询;清理作业先检查是否已有同名删除批次正在执行,若有则直接返回,避免重复启动;随后使用配置的批次大小调用顺序批量删除,并清理由批处理自身产生的已完成批次记录。
Flowable 8.0.0 还改进了历史清理,限制一次批量删除涉及的子流程实例数量。这进一步说明清理工作的核心是控制每批影响范围,而不是追求一次删完。
批次大小、时间窗口和限流要一起设计
100 只是官方默认批次大小,不是所有数据库的最优值。单实例数据很少时可以适当提高;一个实例包含大量会签、变量和子流程时,即使 100 个实例也可能形成很大的事务压力。
生产调参应观察每批持续时间、删除行数、事务日志增量、锁等待、数据库 CPU/I/O、复制延迟和在线审批 P95。达到任一保护阈值就暂停或降低速率。清理窗口应避开月末、结算日和集中导入,不要假设凌晨一定无业务。
首次治理多年积压时,建议按最早时间段逐步推进,并将“补历史欠账”和“每天增量保洁”分成两套节奏。等积压清空后,再用较小、稳定的日常批次维持水位。
六、工程实现与系统集成
为什么不建议直接写 DELETE SQL
历史流程实例关联活动、任务、变量、明细、身份关系、批注、附件和字节数据,企业二开还可能增加业务审计表。直接删除主表可能留下孤儿数据;手写多表删除又容易遗漏版本变化、新增表和引擎扩展。
直接大事务删除还会放大锁、日志和恢复风险。优先使用 Flowable 提供的历史删除与批处理 API,让引擎按其数据模型清理关联记录。只有经过完整依赖梳理、官方版本验证和恢复演练后,才考虑数据库级专用归档工具。
清理是不可逆操作。执行前必须完成备份或可验证归档,抽样核对实例完整性,并确认法务保留、审计冻结和未决争议数据不会被误删。
用热、温、冷三层建立历史生命周期

热数据服务日常待办追溯和近期已办查询,保留在流程主库;温数据服务较低频审计,可进入只读归档库;冷数据用于长期合规,采用不可变存储或离线归档。删除动作只发生在完成归档校验、保留期判断和法务冻结检查之后。
保留周期不宜全公司一刀切。请假流程可能保留两年,合同审批和财务审批可能需要更长时间,测试流程则可以很短。策略维度至少包括租户、流程类型、结束时间、数据分类、合规期限和冻结标记。
归档不是“复制完就算成功”。需要保存实例与业务单据的关联键、流程版本、关键轨迹、意见和必要变量,校验记录数与摘要,并定期演练检索和恢复。若归档库无法查询,所谓冷数据只是不可用的备份。
七、安全、性能与治理要求
分区表与读写分离可以做,但不是第一步
按时间分区能让部分时间范围查询和过期分区回收更高效,但 Flowable 历史数据跨多张表关联,数据库产品的分区规则也不同。自行修改建表结构可能增加版本升级、外键关系和官方脚本兼容成本,应在压测与升级演练后实施。
只读副本可以分担历史检索,但必须处理复制延迟,不能把“刚办完立即查询”的强一致场景无条件导向副本。复杂报表更适合增量同步到独立查询库,而不是在流程主库叠加更多索引和聚合 SQL。
私有化部署要把治理能力产品化
长期可维护的平台应提供历史容量看板、保留策略、清理任务、批次进度、失败重试、法务冻结、归档校验和审计日志,而不是让运维人员周期性手工执行脚本。云程低代码开发平台在工作流能力建设中,也应把这些生命周期规则作为平台治理配置,与流程设计、业务单据和权限审计统一起来。

多租户环境还应设置租户级配额和增长预警。某个租户的高频流程或大变量不应耗尽共享流程库;清理和归档也要保留租户隔离,不能用全局批次掩盖局部异常。
八、平台落地、测试与选型
一套可落地的生产实施顺序
- 盘点版本、历史级别、数据库类型、表容量和保留义务,确认 Flowable 7/8 不再使用旧异步历史方案。
- 从 APM 和数据库中找出真正影响审批的前十条 SQL,保留执行计划与基线指标。
- 修正无边界查询、深分页、全量变量加载和同步大报表,再评估是否需要新索引。
- 选择一个低风险流程,定义热、温、冷周期以及冻结规则,完成归档可读性验证。
- 在预生产复制真实规模数据,测试不同批次大小,记录锁、日志、I/O 和在线时延。
- 生产先清理最老的一小段数据,设置自动暂停阈值,并核对业务单据与历史轨迹。
- 积压清空后启用稳定的增量 Housekeeping,把容量、批次和失败状态纳入日常监控。
常见问题
1. 历史级别改成 none,就能解决所有性能问题吗
不能。它会失去流程追溯能力,而且不能清除已有历史数据。企业审批通常需要审计,应该在合规边界内减少明细,而不是简单关闭历史。
2. 给所有结束时间和业务字段建联合索引是否更快
未必。索引只有匹配真实查询才有价值,过多索引会拖慢写入与删除。应通过执行计划、数据选择性和线上指标验证。
3. 历史数据能否每晚一次性全部清完
不建议。大事务容易造成日志、锁和 I/O 峰值。Flowable 官方清理本身采用批处理,企业还应增加限流、暂停阈值和分阶段消化积压。
4. 历史库独立出去后,主库就不会受影响吗
只有当写入、查询与同步链路都被重新设计后才可能明显隔离。仅复制一份数据而在线查询仍打到主库,不会解决问题;复制延迟和归档一致性也需要治理。
九、结论:性能优化的本质是控制历史数据生命周期
Flowable 历史表的性能问题,本质上不是“表大了怎么办”,而是企业是否知道哪些历史必须生成、哪些必须在线、哪些可以归档、何时可以安全删除。历史级别控制入口,查询与索引控制在线成本,分层保留控制存量,官方批处理控制删除冲击,监控和演练控制生产风险。
记住五句话:先用慢 SQL 证明瓶颈;audit 通常比无差别 full 更合理;Flowable 7/8 不再支持异步历史持久化;清理要走引擎批处理并小步限流;归档必须可查询、可校验、可审计。做到这些,历史数据才能从“不断膨胀的负担”变成“可治理的审计资产”。

浙公网安备 33010602011771号