Skip to content

关于表设计的思考 ​

四种方案横向对比 ​

方案概述代表平台优点缺点
方案一:元数据驱动 + 动态物理表元数据定义结构,后台动态执行CREATE TABLE/ ALTER TABLE生成物理表。- OutSystems - Salesforce (部分实现) - JVS低代码平台- 查询性能高:利用物理表原生索引,性能最好。 - 维护直观:结构在数据库层面清晰可见。 - 事务支持强:完整支持ACID特性。- 扩展性差:增加租户/表单会产生海量表,元数据膨胀。 - DDL风险高:大量ALTER TABLE导致锁表,易引发DDL风暴。 - 并发支持弱:高并发下结构变更困难。
方案二:纯JSON列存储所有业务数据存储在一张或多张表的单个JSON/JSONB列中,表结构固定。- MongoDB - Firebase - 部分轻量级低代码工具- 灵活性极高:无需预定义字段,可任意嵌套。 - 开发速度快:读写逻辑简单,类MongoDB的API丰富。 - 无DDL负担:彻底消除DDL操作。- 查询效率低:对JSON内部字段的查询和聚合性能有限,复杂JOIN困难。 - 事务支持弱:多数NoSQL跨文档事务能力有限。 - 运维成本高:存储空间放大,对DBA技能要求高。
方案三:固定核心表 + 行内JSONB(混合存储)一个“核心表”存放固定字段,一个“扩展表”存储动态字段,扩展表内用JSONB列存储所有动态属性。- 明道云 - 简道云 - NocoBase - Appsmith - Retool- 平衡灵活与性能:高频查询走固定列,低频动态属性用JSONB。 - 避免DDL风险:扩展表的列是可变的,但结构固定。 - 支持查询:JSONB字段支持高效查询和部分索引。- 实现复杂度中等:需设计清晰的数据路由和查询转换逻辑。 - 查询有一定开销:跨表查询和JSONB内部条件查询比方案一略差。 - 元数据管理复杂:需维护一套映射关系。
方案四:冗余所有类型列(预先预留列)预先定义多个VARCHAR、INT等类型的列,将动态字段映射到这些物理列上。- 早期Salesforce (Flex Table) - 一些已淘汰的内部自研系统- 实现非常简单:物理表固定,应用逻辑直接。 - 规避DDL操作:字段增减不改变表结构。 - 与ORM集成好:可被多数ORM轻易映射。- 存储和行数浪费严重:多数预留字段为空,浪费空间,且直接限制总列数(如1024列)。 - 字段名无业务含义:VARCHAR_1,INT_2,维护和调试困难。 - 扩展性差:预留列总数有限,总有耗尽的一天。

方案三(混合存储)是综合来看最务实、最流行的选择。 ​

  • 原理:它将核心、高频查询的字段保留为物理列,而让大量动态、非核心字段进入JSONB扩展列。这样,既利用关系型数据库的强大查询能力保证了高性能,又获得了类似NoSQL的灵活性。
  • 流行原因:该方案完美避开了方案一(DDL风暴)、方案二(查询弱)、方案四(空间浪费)的致命缺陷,同时在实现成本、未来扩展性、交付稳定性和查询性能之间取得了最佳平衡。

最终建议 ​

  • 采用方案一(动态物理表)作为核心架构,并用好 MySQL 8.0 Online DDL + gh-ost 规避风险。
  • 允许在部分非核心表中使用 JSON 列(如操作日志、临时附件描述),但不作为主要数据存储方式。
  • 绝对避免 EAV 模型(那篇文章对这一点是完全正确的)。

如果你决定走方案一,我可以继续提供:

  • 基于 MyBatis-Plus 的动态建表/改表代码框架
  • 元数据管理表设计(entity_meta、field_meta)
  • gh-ost 集成到 Spring Boot 的自动化方案
  • 满足等保审计的字段变更日志记录

MySQL 5.7 vs 8.0: 核心功能支持对比 ​

功能维度MySQL 8.0MySQL 5.7对方案一/方案三的影响
🔧 JSON支持完整(含高性能函数)基础(仅基础函数)方案三性能与开发体验差距大
⚡ Online DDL5.6支持,5.7增强,更稳定支持(仅允许“同时读写”)方案一加列、建索引可实现无锁变更
💣 原子DDL支持原子性不支持原子性方案一有数据不一致风险
📈 JSON 虚拟列索引可在虚拟列上直接创建索引需使用“存储列”方案三为高频字段加索引需增加存储开销
🚀 INSTANT ADD COLUMN支持不支持方案一加列会重建全表,大表执行缓慢
🔒 列级权限支持不支持方案一无法实现字段级精细授权
🌐 角色(Role)支持不支持方案一权限管理更复杂

MySQL下载链接:直接从 MySQL 官方下载页面获取最新的社区版:https://dev.mysql.com/downloads/mysql/。