从 ER 图到 DDL:一套可复现的数据库建模流程 数据库设计的交付物常常只停留在三样东西上一张截图、一份 Word、一段口口相传的约定。等到半年后要加字段、要评审、要排查线上表结构为什么和文档不一致时才发现没有可执行的来源。这篇记录一套实际在用的流程把 ER 图从图变成可执行的模型再把它纳入版本管理和 CI 校验。全程只用文本和命令任何一次变更都能diff。一、先建一条流水线整条链路只有五步关键是每一步的输出都是下一步的输入中间不落人工业务讨论实体/关系/基数 ↓ DBML 文本模型 → 进 Git评审即 diff ↓ 导出 DDL / PDF / 图片 → 交付物 ↓ CI 校验 数据字典生成 → 自动不靠人工维护 ↓ 逆向解析线上库 → 反查模型是否漂移这条链路的判定标准很硬如果某一步必须靠人手工复制粘贴它迟早会失效。下面逐步拆开。二、第 1 步讨论阶段不要把模型锁死实体和关系的定稿几乎都在评审会上发生这时有一个常见误区——会上就直接在建模工具里定字段类型、定主键名。问题是讨论期变更频繁过早锁定结构会让每次调整都变成一次返工。这个阶段真正需要的是能边聊边改、所有人都看得到的画布。把实体、属性、基数先摆出来字段类型可以只写粗略意图比如金额小数“时间戳”。上图是这种用法的一个例子用的是诺智白板NuromBoard实体和关系直接落在画布上字段以批注形式挂在实体旁边讨论记录留在同一块画布会后不必再翻聊天记录。值得一提的是一体化画布类工具的 AI 建板能力——把业务场景用一句话描述出来先得到一份实体与关系的草稿再在画布上改。它的价值不在少画几个框而在于草稿本身就是可编辑对象不需要照着重新画一遍。这一步的产出一份达成共识的实体关系草图。注意它还不是模型别急着往生产走。三、第 2 步用 DSL 把模型写成文本讨论定稿后立刻转成文本模型。DBML 是目前比较顺手的一种声明式语法dbdiagram.io 用它作为输入格式右边实时渲染Table users { id int [pk] name varchar email varchar [unique] created_at datetime } Table orders { id int [pk] user_id int [ref: users.id] amount decimal status varchar } Table order_items { id int [pk] order_id int [ref: orders.id] product_id int [ref: products.id] quantity int }转成文本的好处立刻显现可评审git diff直接看出哪个字段改了、哪个外键转向了不必打开图形工具对比两张截图。可生成DDL、数据字典、PDF 全部由这一份文本派生不会出现文档和代码两套说法。可校验外键指向不存在的表、字段名重复这类问题能在 CI 里报错而不是等到建表失败。常见坑DBML 里不写[ref: ...]关系线不会出现导出的 DDL 里也不会有外键。很多人第一次用会以为工具不支持外键其实是没声明。建议的顺序是先补全实体和字段再补ref约束最后统一校对基数方向多对一、一对多、-一对一。四、第 3 步导出 DDL 并处理方言差异导出后的 DDL 大致长这样CREATETABLEusers(idINTPRIMARYKEY,nameVARCHAR(255),emailVARCHAR(255)UNIQUE,created_atDATETIME);CREATETABLEorders(idINTPRIMARYKEY,user_idINT,amountDECIMAL(10,2),statusVARCHAR(64),FOREIGNKEY(user_id)REFERENCESusers(id));这一步最容易吃亏的地方是方言。同一个模型导出到 MySQL、PostgreSQL、Oracle类型映射并不一致模型里的类型MySQLPostgreSQL注意点int主键INTINTEGER/SERIAL自增写法不同PG 现在更推荐GENERATED ... AS IDENTITYdecimalDECIMAL(10,2)NUMERIC(10,2)精度语义一致名称不同varcharVARCHAR(255)VARCHAR(255)无长度限制时 PG 可直接用TEXTdatetimeDATETIMETIMESTAMP时区处理差异明显务必确认是否带WITH TIME ZONE建议导出的 DDL 不要直接对生产执行。先落到仓库里当作 schema 的事实来源再用迁移工具Flyway、Liquibase、Atlas、Alembic 等基于它生成变更脚本。这样改模型和改库之间有一层可控的边界。五、第 4 步接进 CI让校验自动化模型进了仓库就可以像代码一样管起来。下面这个GitHub Actions配置做两件事模型文件变更时校验语法并自动生成数据字典产物name:db-model-checkon:pull_request:paths:-schema/**/*.dbmljobs:validate:runs-on:ubuntu-lateststeps:-uses:actions/checkoutv4# DBML 的 CLI 需要 Node 18 以上-uses:actions/setup-nodev4with:node-version:20-name:解析校验语法或 ref 有错会直接失败run:|npx -p dbml/cli dbml2sql schema/main.dbml -o /tmp/main.sql-name:生成各数据库方言的 DDLrun:|mkdir -p dist npx -p dbml/cli dbml2sql schema/main.dbml --postgres -o dist/schema.pg.sql npx -p dbml/cli dbml2sql schema/main.dbml --mysql -o dist/schema.mysql.sql-uses:actions/upload-artifactv4with:name:schema-artifactspath:dist/几点说明dbml2sql不指定方言时默认输出 PostgreSQL--mysql、--mssql、--oracle可切换。用-o输出到文件。用npx -p dbml/cli而不是npx dbml/cli前者的语义是安装这个包并执行其中的命令后者会把包名当成命令名去找。官方 README 里另一种常见写法是npx -p dbml/cli dbml2sql schema.dbml -o schema.sql效果一致。如果你的模型拆成了多个文件DBML 的模块系统入口文件传project.dbml即可CLI 会自动解析 import。这样任何一次改模型都要过 CI字段命名、外键引用、类型合法性在合并前就会被拦住。数据字典也不再需要人工维护——它由模型派生天然不会过期。六、第 5 步用逆向工程反查模型漂移再规范的流程也挡不住有人在生产库上直接加了字段。所以需要定期把线上库反向解析成模型和仓库里的版本对比。推荐做法dbml/cli自带的db2dbml可以直接连库生成 DBML省掉中间格式转换# 从线上库重新生成一份模型与仓库中的版本对比npx-pdbml/cli db2dbml mysql\mysql://user:passhost:3306/dbname\-o/tmp/live.dbmlgitdiff--statschema/main.dbml /tmp/live.dbml如果两边有明显差异说明模型发生了漂移要么是有人绕过流程改了库需要补模型或回滚要么是模型本身该更新了但没提交。无论哪种都需要人工确认但至少能发现。纯命令行的另一条路是先用mysqldump导出结构再解析适合不方便直连生产库的场景# 只导结构不导数据去掉注释与自增计数等噪声便于 diffmysqldump --no-data --skip-comments --skip-add-drop-table\-h$DB_HOST-u$DB_USER-p$DB_PASS$DB_NAMEschema/live.sql npx-pdbml/cli sql2dbml schema/live.sql--mysql-o/tmp/live.dbmlMySQL 技术栈下还有一个图形化办法Workbench 的Database → Reverse Engineer连上库后自动生成 EER 图再导出成 SQL 与模型文件。面向工程化沉淀的团队还可以用 PDManer 这类工具既能正向生成 DDL也能逆向解析已有库并直接导出数据字典适合统一字段口径、把模型当资产维护。需要注意项目状态PDManer 仓库已归档停更官方由 PDMaas 承接后续迭代官方说明为功能基本无损继承。存量工程可继续使用新项目建议直接从 PDMaas 起步避免后续迁移成本。七、工具怎么选按环节分工而不是找一款打通全程走到这里可以看得很清楚这条链路上每个环节合适的工具往往不是同一个。环节需要的能力可选工具讨论对齐画布内可编辑、多人协作、讨论留痕诺智白板NuromBoard、Draw.io、Lucidchart文本建模DSL 语法、实时渲染、导出 DDLdbdiagram.io、MermaiderDiagram工程化建模正反向工程、数据字典PDManer / PDMaas、MySQL Workbench版本管理文本格式、可 diffMermaid、DBML 文件几点经验不必强求一款工具打通全程。讨论期用画布、建模期用 DSL、落地期用迁移工具各取所长接口就是文本。选工具先看输出格式。导出能力受免费档限制的工具文档数、导出次数要在选型阶段就确认否则模型做完了导不出来。纯绘图工具要认清定位。Draw.io 这类工具免费、可离线、导出 SVG/PNG 方便但它不产生可执行 DDL适合做结构说明图不适合当模型源头。离线和合规涉及敏感字段或核心业务结构时优先本地工具或脱敏后再上传在线服务。文档渲染场景README、Confluence、Notion用 Mermaid 的erDiagram更省事评审即 diffmermaid erDiagram CUSTOMER ||--o{ ORDER : places ORDER ||--|{ LINE-ITEM : contains CUSTOMER }|..|{ DELIVERY-ADDRESS : uses 八、几个踩过的坑把截图当交付物。半年后没人能说清某字段为什么是varchar(64)因为依据只存在某台电脑的本地文件里。模型与库各改一套。没有逆向校验的流程漂移是必然事件不是概率事件。DDL 直接上生产。缺少迁移脚本这一层回滚时会非常被动。忽略方言差异。同一个datetime在 MySQL 和 PostgreSQL 上的时区语义不同跨库项目要单独验证。为用不上的专业能力付费。重型建模工具能力强学习与维护成本同样高除非团队已有明确规范与长期收益。九、小结这套流程的核心不是工具而是把模型的存在形式从图换成文本。一旦模型是文本评审、校验、生成、版本管理这些能力就都能接上去工具只是每个环节的实现选择。建议先用一个真实的小场景比如订单与用户走完一遍全流程实际卡点比参数表更有说服力。