资讯动态

OA办公系统数据库设计:从容量估算到动态表单完整指南

发布时间:2026/10/9 16:07:18 来源:尧图企业网站定制
简介这份《OA办公系统大数据库设计.doc》是一份面向OA办公自动化管理系统设计与开发人员的完整数据库设计说明文档核心目标是将业务数据分析结果整理为可供开发的计算机模型从而指导物理数据库的构建。文档选用MSSQL SERVER 2008 R2作为数据库平台库名为OASYSDB/OA系统数据库内容涵盖引言、数据字典设计、数据库设计三大部分其中数据字典对人员编号、姓名、性别、出生年月、部门、岗位、联系电话、工资等核心数据项的类型、位置、描述均有细致定义数据库设计则涉及系统物理结构、表设计、表间关联、存储过程、触发器及Job设计为系统开发、验收、评审和测试人员提供统一的数据规范与实现参考。资源为1个doc文档大小约211KB目前已吸引144人学习适合OA系统研发人员、数据库设计人员及相关项目评审人员查阅借鉴。1. OA办公系统大数据库设计先搞清楚这套库在解决什么很多从业者第一次接触 OA 办公系统数据库设计是从一份《OA办公系统大数据库设计.doc》这样的文档名开始的。这类文档名里的“大”说的是这套库的表多、关系深、生命周期长——组织、权限、流程、表单、文件、消息都要装进同一套模型里一次设计就要应对好几年的数据增长。它不是大数据组件不是 Hadoop、数仓那一套而是典型的业务关系型数据库设计。好的设计能让 OA 在后续加表单、加审批流、加报表时不动主干不好的设计会在需求一到就频繁改表加班补数据。下文按“容量估算 → 组织权限 → 流程表单 → 避坑 → 上线自检”展开适合正在设计 OA 库、或准备二次开发老 OA 系统的开发者和团队直接参照。2. 容量与选型先算账再谈建表2.1 为什么这套库是“大数据库”而不是“大数据”OA 系统的用户量通常只有几百到几千日活并发也不会太高正常企业的 OA 根本不需要互联网级的吞吐设计。真正“大”的是表的数量和关系复杂度组织架构、权限、流程实例、审批任务、动态表单、文件索引、消息待办这些模块加起来轻松超过 100 张表。我习惯把这张库的表拆成四类来看基础数据用户、部门、岗位、菜单、权限数据角色、角色菜单关联、用户角色关联、业务数据流程实例、任务、表单、审批记录、系统数据文件索引、消息、操作日志。设计文档的骨架本质上就是把这四类数据的模型定清楚。这里有一个常见误区看到标题里的“大数据”就往分布式上靠。OA 的业务特征是 OLTP 为主、少量报表统计数据量到千万级已经算很大的部署。在单实例 MySQL 上做合理的表结构、索引和归档策略远比引入分库分表、消息队列更可靠成本也更低。我一般会先按单实例方案设计把容量估算写在最前面只有当估算结果明确超出单机承受范围时才考虑按模块拆库。2.2 容量估算公式一张表算出库要多大动手建表前先回答一个问题这台库预计要装多少数据不建议对每张表做精确估算只算最核心的两类流程实例/任务流水以及文件索引。流程与表单流水可以按下面的参数估算。参数取值参考说明在职用户数500按峰值取包含离职后需要保留的账号日活比例60%OA 的日活比互联网产品高取 0.5~0.7 比较稳人均日交互次数20发起流程、审批、查看待办、传附件等合计平均行大小1 KB流程实例和任务记录的平均大小每年工作日250内部系统按每年 250 个工作日估算保留年限5 年企业档案要求的常见保留周期计算公式容量 ≈ 用户数 × 日活比例 × 人均日交互 × 平均行大小 × 250 × 保留年限。代入上面的取值500 × 0.6 × 20 × 1 KB × 250 × 5结果是 7.5 GB 左右。这个量级对任何单实例数据库都没有压力但它的价值在于让你心里有底核心业务表五年内也就是千万行以内建索引、做分页查询时完全不需要考虑分区表。文件要单独估算。500 个用户平均每人每月传 2 个 2 MB 附件一年就是 500 × 2 × 12 × 2 MB约 24 GB远超业务表本身。所以文件本体一定不能塞进数据库库表只保存文件索引信息这一点在后面的存储设计里会展开。2.3 存储选型与基础参数MySQL 8.x 的常规配置容量算完接下来是选型。自建 OA 最常见的底座是 MySQL 8.x 单实例老项目用 SQL Server 的也不少但设计思路通用。如果从零开始我一般会固定几项基础参数引擎统一 InnoDB事务隔离级别用 READ-COMMITTED字符集 utf8mb4排序规则先用 utf8mb4_0900_ai_ci——这是 MySQL 8.0 的默认值对中英文混合排序表现正常如果项目对中文排序有特殊要求不要想当然造几十条数据实测排序结果再定。时区统一成东八区连接层指定 time_zone避免半夜跑批时时间错乱。内存参数里最重要的是 innodb_buffer_pool_size按物理内存的 60%~70% 设置即可。8 GB 内存的机器给 5 GB16 GB 给 10 GB这能让热点数据和索引尽量留在内存。max_connections 设置为 200 一般够用OA 是内部系统连接数冲高往往不是并发高而是慢查询把连接占住了。sort_buffer_size 保持 2 MB 默认值不要调大否则高并发下内存会被排序缓冲区吃光。这些参数在配置文件的 [mysqld] 段修改改完重启生效属于上线前就固定好的基础项。3. 组织与权限模型六张表管住人、部门和菜单3.1 用户、部门、角色的核心建表 SQL组织与权限是 OA 的地基几乎所有业务表都要引用用户表和部门表。常见做法是六张表用户、部门、角色、菜单、用户角色关联、角色菜单关联。下面给出最核心的四张表菜单表结构简单后面按相同套路补即可。-- 部门表 CREATE TABLE sys_dept ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 部门ID, name VARCHAR(64) NOT NULL COMMENT 部门名称, parent_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 上级部门ID0为根, ancestors VARCHAR(500) NOT NULL DEFAULT / COMMENT 祖先链格式如 /1/12/, sort_no INT NOT NULL DEFAULT 0 COMMENT 排序号, status TINYINT NOT NULL DEFAULT 1 COMMENT 1启用 0停用, create_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), update_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (id), KEY idx_parent_id (parent_id), KEY idx_ancestors (ancestors(191)) ) ENGINE InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT 部门表; -- 用户表 CREATE TABLE sys_user ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 用户ID, dept_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 所属部门ID, username VARCHAR(64) NOT NULL COMMENT 登录账号, password VARCHAR(100) NOT NULL COMMENT 密码哈希不要用MD5加密原文, nickname VARCHAR(64) NOT NULL DEFAULT COMMENT 姓名, mobile VARCHAR(20) NOT NULL DEFAULT COMMENT 手机号, email VARCHAR(128) NOT NULL DEFAULT COMMENT 邮箱, avatar VARCHAR(255) NOT NULL DEFAULT COMMENT 头像地址, status TINYINT NOT NULL DEFAULT 1 COMMENT 1启用 0停用, deleted TINYINT NOT NULL DEFAULT 0 COMMENT 逻辑删除0正常 1已删, create_by BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 创建人ID, update_by BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 更新人ID, create_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), update_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (id), UNIQUE KEY uk_username (username), KEY idx_dept_id (dept_id), KEY idx_status (status) ) ENGINE InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT 用户表; -- 角色表 CREATE TABLE sys_role ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 角色ID, role_name VARCHAR(64) NOT NULL COMMENT 角色名称, role_key VARCHAR(64) NOT NULL COMMENT 角色标识如 admin/manager/employee, sort_no INT NOT NULL DEFAULT 0 COMMENT 排序号, status TINYINT NOT NULL DEFAULT 1 COMMENT 1启用 0停用, create_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), update_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (id), UNIQUE KEY uk_role_key (role_key) ) ENGINE InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT 角色表; -- 用户角色关联表 CREATE TABLE sys_user_role ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, user_id BIGINT UNSIGNED NOT NULL COMMENT 用户ID, role_id BIGINT UNSIGNED NOT NULL COMMENT 角色ID, PRIMARY KEY (id), UNIQUE KEY uk_user_role (user_id, role_id), KEY idx_role_id (role_id) ) ENGINE InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT 用户角色关联表;这段 SQL 里有几个值得说明的细节。用户表的 dept_id 不建物理外键而是保留数字引用这是为了让部门调整时不必顾虑外键约束阻塞删除用户时也不会被外键拦下逻辑删除就够。ancestors 字段是部门树的冗余路径索引上只取前 191 个字符部门树深度在 10 层以内时不会有问题。密码字段用 VARCHAR(100)因为 bcrypt 哈希结果是 60 个字符左右MD5 的 32 位长度根本装不下这个字段长度直接决定你将来能不能顺利升级认证方式。3.2 部门数据权限ancestors 字段怎么设计、怎么查菜单权限解决“能看到哪些功能”数据权限解决“能看到哪些人的数据”。OA 里最常见的数据权限是部门隔离部门经理只能看本部门及子部门的单据。这个需求靠部门表的 ancestors 字段就能实现。ancestors 存的是从根到父部门的完整路径链例如部门 12 的祖先链是 /1/12/它的子部门 123 的祖先链是 /1/12/123/。插入新部门时先查父部门的 ancestors再拼接父部门 id。查询“部门 123 及其所有子部门下的用户”SQL 是这样的SELECT u.id, u.username, u.nickname FROM sys_user u INNER JOIN sys_dept d ON u.dept_id d.id WHERE d.id 123 OR d.ancestors LIKE /1/12/123/%;这里d.id 123覆盖本部门ancestors LIKE /1/12/123/%覆盖所有子孙部门。按前缀匹配能用上 idx_ancestors 索引部门数据量不大时性能没有问题。维护时要留意如果部门从 A 节点移动到 B 节点需要批量更新该部门及所有子部门的 ancestors常见做法是在事务里先查出子树再逐个拼接新路径这属于低频操作正确性优先于性能。3.3 账号字段的三个细节密码、逻辑删除、审计账号表最容易被低估的是三个细节。第一登录账号的唯一索引不能只建在 username 上。用户离职后做逻辑删除username 还占着新员工入职想用同一个账号就会报唯一键冲突。常见解法是把唯一索引改成(username, deleted)逻辑删除时把 deleted 置为不同的数字比如正常 0删除后填主键 id这样既保留了删除记录又允许账号被重新使用。第二审计字段 create_by、update_by、create_time、update_time 必须齐套否则出问题要追溯“谁在什么时候改了什么”时完全无能为力。第三status 字段的默认值要写 1新账号默认启用批量导入用户时导入程序要显式校验账号、手机号格式避免脏数据直接进表。这几点在写建表语句时顺手就做了后面改起来成本高得多。4. 流程审批与动态表单OA 数据库最难的建模点4.1 动态表单的三种建模方式以及为什么选扩展 JSON流程审批是 OA 和普通管理系统的分水岭。请假单、报销单、用印申请每种单子的字段都不一样而且业务部门随时会要求加一个字段。表单建模通常有三种方案对比后选择取决于项目实际。方案优点缺点适用场景硬编码宽表查询直观报表好写字段有强约束加字段就要 ALTER TABLE表单类型一多就失控表单固定、数量很少的演示项目EAV 属性表加字段不用改表模型万能查询要把行转列SQL 复杂数据量一大性能明显下降属性极少、没有高频列表查询的场景主表 JSON 扩展兼顾灵活性和查询性能公共字段拉平依赖数据库 JSON 能力需要理解生成列和函数索引大多数 OA 动态表单场景我一般直接选第三种公共字段建列动态字段放 JSON。流程实例表存流程本身的公共属性表单数据表存每种单据的 JSON 内容。这样加字段时应用层改一个配置数据库完全不动。JSON 字段不是黑匣子需要参与查询的字段用生成列抽出来建索引后面的小节会具体演示。4.2 流程实例与任务节点两张表落地完整状态机流程引擎的核心是实例和任务。实例表示“这一单走到哪了”任务表示“当前这一步该谁处理”。状态机中最少要有草稿、审批中、通过、驳回、撤回、终止六种状态落到表里就是这个样子-- 流程实例表 CREATE TABLE oa_process_instance ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 实例ID, process_key VARCHAR(64) NOT NULL COMMENT 流程定义Key如 leave_approve, instance_no VARCHAR(32) NOT NULL COMMENT 流程实例编号如 PR20250617001, title VARCHAR(255) NOT NULL COMMENT 单据标题列表页直接展示, form_key VARCHAR(64) NOT NULL COMMENT 表单类型Key, status TINYINT NOT NULL DEFAULT 0 COMMENT 0草稿 1审批中 2通过 3驳回 4撤回 5终止, current_node VARCHAR(64) NOT NULL DEFAULT COMMENT 当前节点Key, initiator_id BIGINT UNSIGNED NOT NULL COMMENT 发起人ID, create_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), update_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (id), UNIQUE KEY uk_instance_no (instance_no), KEY idx_initiator_status (initiator_id, status) ) ENGINE InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT 流程实例表; -- 流程任务节点表 CREATE TABLE oa_process_task ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 任务ID, instance_id BIGINT UNSIGNED NOT NULL COMMENT 流程实例ID, node_key VARCHAR(64) NOT NULL COMMENT 节点Key如 manager_approve, node_name VARCHAR(64) NOT NULL DEFAULT COMMENT 节点名称给待办列表展示用, assignee_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 当前办理人ID, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待办 1通过 2驳回 3已转办 4已撤回, comment VARCHAR(500) NOT NULL DEFAULT COMMENT 审批意见, version INT NOT NULL DEFAULT 1 COMMENT 乐观锁版本号, create_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), update_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (id), KEY idx_assignee_status (assignee_id, status), KEY idx_instance_node (instance_id, node_key) ) ENGINE InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT 流程任务节点表;状态值用 TINYINT 而不是字符串是为了索引更小、查询更快状态含义在应用层用枚举映射。任务表必须保留 node_name 这个冗余字段待办列表页要频繁展示节点名称每次去流程定义表解析 JSON 效率太低。version 字段是乐观锁处理会签并发时的作用在避坑章节单独讲。审批记录建议单独建一张 oa_process_record存 instance_id、task_id、operator_id、action、comment、create_time这张表只增不改是审计和追溯的依据。查询某单的完整流转历史时按 instance_id 和 create_time 排序即可。4.3 表单数据的 JSON 扩展字段建表、索引与查询流程实例表只关心流程状态具体填了什么内容要落到表单数据表。这张表的核心是 JSON 列CREATE TABLE oa_form_data ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 表单数据ID, instance_id BIGINT UNSIGNED NOT NULL COMMENT 流程实例ID, form_key VARCHAR(64) NOT NULL COMMENT 表单Key对应每种单据类型, form_data JSON NOT NULL COMMENT 动态表单内容如 {days:3,reason:年假}, version INT NOT NULL DEFAULT 1 COMMENT 表单版本号防止覆盖提交, create_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), update_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (id), UNIQUE KEY uk_instance_form (instance_id, form_key), KEY idx_form_key (form_key) ) ENGINE InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT 动态表单数据表;使用上有个容易踩的坑不要在 WHERE 里直接写JSON_EXTRACT(form_data, $.days) 3这样做全表扫描数据一多查询就慢。规定一个原则只有高频过滤的字段才抽出来建索引。比如请假单的“请假天数”经常要按大于等于 3 天筛选就用生成列把它变成普通列ALTER TABLE oa_form_data ADD COLUMN leave_days INT GENERATED ALWAYS AS (CAST(JSON_UNQUOTE(JSON_EXTRACT(form_data, $.days)) AS UNSIGNED)) STORED, ADD INDEX idx_leave_days (leave_days);生成列是 STORED数据写入时就会物化查询条件直接写成leave_days 3就能走索引。注意只对真正高频筛选的字段做这件事为每个 JSON 字段都建生成列会让表变得臃肿得不偿失。4.4 附件与消息的存储数据库只管索引不管文件本体附件是 OA 里最容易被设计错的模块。正确的做法是文件本体放文件服务器或对象存储数据库只登记一份文件索引记录它在哪、是谁传的、属于哪个业务单据。文件索引表的结构很简单CREATE TABLE oa_file_store ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 文件ID, file_name VARCHAR(255) NOT NULL COMMENT 原始文件名, file_path VARCHAR(255) NOT NULL COMMENT 文件存储路径或对象Key, file_size BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 文件字节数, file_md5 CHAR(32) NOT NULL DEFAULT COMMENT 文件MD5用于秒传和去重, biz_type VARCHAR(32) NOT NULL DEFAULT COMMENT 业务类型如 expense_attachment, biz_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 业务主键ID, uploader_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 上传人ID, create_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), PRIMARY KEY (id), KEY idx_biz (biz_type, biz_id), KEY idx_uploader_time (uploader_id, create_time) ) ENGINE InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT 文件索引表;文件表不存文件内容这是铁律。把附件当 BLOB 存进数据库短期内看不出问题等到库文件膨胀到几十 GB备份和恢复都会变成噩梦。文件索引表还有一层用处定期扫描biz_type biz_id查不到对应单据的记录这些就是用户上传后没有提交的废文件可以在存储端定时清理。消息待办表同理只记录接收人、标题、内容摘要和业务关联 ID正文超过一定长度就存 TEXT列表查询只需要按receiver_id is_read create_time索引取前 50 条。5. 避坑指南OA 数据库设计中 5 个高频翻车点5.1 硬编码宽表一加字段就加班现象每种审批单都设计成独立宽表字段全部拉平上线后发现业务部门每个月都要调整表单字段每次加字段都要 ALTER TABLE发布窗口经常被阻塞到凌晨。原因建模时图查询方便忽略了 OA 表单字段天然高频变动的特点。宽表在字段固定、数量少的场景是好方案但 OA 的单据类型多硬编码等于把需求变动直接引到数据库结构上。解决公共字段拉平动态字段进 JSON按前面 4.3 节的方案改造。改造时给旧表加一个 JSON 列把新增字段都放进去存量数据不动老查询照常走原来的列新查询走 JSON这是成本最低的平滑迁移路径。5.2 事务里夹带文件上传锁等待堆到报警现象提交报销单的接口偶尔超时数据库监控里出现大量锁等待连接数飙高业务高峰期整个 OA 变卡。原因代码里把文件上传写在业务事务里上传走网络 IO一次上传耗时几百毫秒甚至几秒数据库连接被事务攥在手里不释放其他事务只能排队等锁。解决调整事务边界。文件先传到临时存储拿到 file_id 后再把业务记录和文件索引的插入放在同一个短事务里完成。如果文件服务不稳定宁可让用户重新上传也不要让数据库事务替网络 IO 背锅。5.3 逻辑删除的幽灵数据现象用户列表偶尔出现已经离职的人部门统计人数偏大或者新导入用户时提示账号已存在但界面上看不到这个账号。原因查询 SQL 漏写了deleted 0条件或者唯一索引建在 username 单列上删除后的账号仍然占着唯一键。解决统一封装数据访问层所有单表查询自动拼接逻辑删除条件不允许业务代码手写裸 SQL唯一索引改成(username, deleted)删除时把 deleted 字段置为主键 id保证同一账号删除后可以重新注册。老代码里散落的select *要专项排查这类问题隐蔽数据量越大越难清理。5.4 会签节点并发重复审批现象一个会签节点有多个审批人两个人几乎同时点“通过”结果同一条任务被更新了两次审批状态和下一步流转逻辑错乱。原因两个请求都先 SELECT 到 statuspending 的任务再各自执行 UPDATE没有做状态校验后更新的覆盖了先更新的。解决用乐观锁。更新语句写成UPDATE oa_process_task SET status 1, comment 同意, version version 1 WHERE id 123 AND status 0 AND version 1;执行后检查影响行数为 0 说明任务已经被别人处理直接提示用户“该待办已处理”。version 从上一节建表 SQL 里带出来这是流程任务表必须加这个字段的根本原因。5.5 日期时间字段存成了 varchar现象按时间范围查审批记录时9 月的数据排在 8 月前面统计月度报表时漏数据不同办公室的同事看到的时间相差 8 小时。原因为了 Excel 导入方便当初把时间存成了2024-06-17 09:30这种字符串查询时按字符串排序和比较结果完全不符合业务直觉。解决新表一律用DATETIME(3)带毫秒精度建表默认值直接用CURRENT_TIMESTAMP(3)应用层统一用同一时区写入。存量数据用STR_TO_DATE转换转换前先抽样校验格式转完后把原字段改成时间类型并重建索引。这个坑看似低级在真实 OA 项目里出现频率相当高。6. 上线前自检跑一条 SQL 验证你的 OA 库设计6.1 数据量与索引体检 SQL表结构全部建完后不要急着写业务代码先跑一条自检 SQL看每张表的体量预期是否和容量估算对得上SELECT table_name, table_rows, ROUND(data_length / 1024 / 1024, 2) AS data_mb, ROUND(index_length / 1024 / 1024, 2) AS idx_mb FROM information_schema.tables WHERE table_schema oa ORDER BY (data_length index_length) DESC LIMIT 15;table_rows是优化器的估算值不是精确行数但能反映量级趋势。重点看两类异常一是某张业务表的数据量远超估算说明可能漏了归档策略二是索引占用接近甚至超过数据占用说明有冗余索引需要逐个核对。我习惯把每张表的索引导出来人工过一遍重点查是否同时存在uk_xxx和idx_xxx指向同一列的情况以及联合索引里有没有左前缀被浪费的字段。6.2 进阶版本把表单注册表加进设计如果想让这套设计走得更远可以增加一张表单注册表把每种表单的字段配置也存进数据库CREATE TABLE oa_form_define ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, form_key VARCHAR(64) NOT NULL COMMENT 表单Key, form_name VARCHAR(64) NOT NULL COMMENT 表单名称, field_config JSON NOT NULL COMMENT 字段定义如 [{name:days,type:int}], status TINYINT NOT NULL DEFAULT 1 COMMENT 1启用 0停用, create_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), PRIMARY KEY (id), UNIQUE KEY uk_form_key (form_key) ) ENGINE InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT 表单注册表;有了这张表新增一种审批单时只需要插一条配置记录前端根据 field_config 动态渲染表单后端校验逻辑也读这份配置业务表和流程表一行都不用改。这是把 OA 从“改代码上线”推向“配置上线”的关键一步。我自己踩过最深的坑就是早年把审批单全做成宽表后来每次加字段都像做手术一样提心吊胆。现在的习惯是先做容量估算把 JSON 扩展字段用起来再拿上面的自检 SQL 过一遍表结构和索引确认没问题才交给业务方试用。这套流程帮你少走弯路希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑