尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

用Python自建数据字典工具:从information_schema采集到增量维护

发布时间:2026/9/25 5:48:37

资讯中心
01
ARTICLE

用Python自建数据字典工具:从information_schema采集到增量维护

用Python自建数据字典工具:从information_schema采集到增量维护
简介面向数据库开发者、DBA及需要撰写数据库设计文档的技术人员这份2.58MB的ZIP压缩包提供了一款可直接运行的数据字典生成工具。工具能自动扫描MySQL、Oracle、SQL Server、PostgreSQL等主流数据库中的表、视图、存储过程、函数与触发器提取字段名、数据类型、长度、是否为空、默认值以及开发注释并按模板输出为Word或HTML文档大幅降低手工整理数据字典的出错概率。压缩包内共16个文件核心为exe主程序配以dll运行库与数据库驱动、XML配置、HTML/CSS/JS页面模板、docx使用说明以及多张gif/jpg操作演示图结构清晰解压后即可试用。目前已有529人学习下载适合在日常开发、项目交接或系统维护中快速建立库表字典、同步更新结构与注释的团队和个人使用。1. 数据字典工具听着像文档导出器实际管的是元数据治理数据字典工具听着像文档导出器实际上解决的是元数据治理问题把数据库里的表、字段、类型、注释、索引和约束反向抽出来整理成一份稳定、可读、可对比的元数据文件。库表一旦超过两百张团队最容易丢的不是代码而是结构语义——老同事调岗后没人说得清 order_id 和 sale_id 到底差在哪。ERP 项目里这个问题更尖锐用友 NC、畅捷通 T 这类系统动辄上千张表设计文档残缺实施方只能靠工具倒推一套 nc 数据字典或 t 数据字典再让业务顾问逐张补注释。这篇文章写给准备选型或自研工具的工程师也写给在只有库没有文档的老系统里做字典的实施同学。核心建议先说在前面工具的价值不在导出那一刻而在持续证明文档和线上库没有漂移。2. 数据字典工具的四种实现路线为什么我推荐直接查系统表做工具之前先想清楚自己处在哪种环境。我见过四类路线现成 JDBC 元数据解析、直接查系统表、解析 DDL 脚本、从运维平台导元数据。别看它们都能产出字典维护成本差别很大选错路线后面全是补丁。2.1 JDBC 元数据解析SchemaSpy 这类现成工具能摸底扛不住交付第一类是用 JDBC 的 DatabaseMetaData 反向读库SchemaSpy、SchemaCrawler、DBeaver 的 ER 图都属于此类。好处是数据库兼容面广MySQL、Oracle、SQL Server 都能连几乎不用写业务代码跑完自动生成网页版字典和关系图。第一次用是挺爽的一条命令全出来。但放到 NC/T 老库上弱点会很快暴露。老库大量表没有 COMMENT生成出来的字典只有字段名业务顾问根本不知道这是干嘛的外键关系常年缺失SchemaSpy 画出的关系图是一片孤岛几千张表全量渲染成网页打开一次要等十几秒没人愿意看。而且它是个黑匣子输出格式、过滤规则都只能靠命令行参数想按 ERP 的模块前缀分组基本做不到。我的判断是这类工具适合对陌生库摸底侦察不适合做要持续维护、带人工注释的交付级数据字典。如果你只是想知道一个陌生库里有哪些表用现成工具划算如果你要把字典当长期资产维护很快会撞上定制这堵墙。2.2 直接查系统表information_schema 才是自研工具的主战场第二类是用数据库系统表做采集。MySQL 看 information_schemaSQL Server 看 sysOracle 看 ALL_TAB_COLUMNS本质都是把元数据暴露成普通表。我自研数据字典工具时只依赖 information_schema原因是它在 MySQL 里最稳定不依赖额外组件字段行为也最可预期。这条路线的好处在于控制力表名、字段名、类型、注释、索引、约束都能用标准 SQL 取到过滤规则完全自定义想排除 tmp_、bak_ 前缀的表很简单输出格式看心情JSON、Markdown、Excel 都行。它读到的就是数据库当下的结构事实后续做增量、对比、审核都是顺理成章的事。边界也清楚系统表不含业务含义注释缺失不会自己补上。所以架构上必须再加一个人工注释层自动元数据和人工业务注释分开存具体做法见第 3 章的 3.2 节。2.3 DDL 解析适合看历史不适合当线上事实第三类是解析 DDL 文档常见于用 Flyway、Liquibase 管理变更的团队建表脚本都在版本库里用 SQL 解析器把 CREATE TABLE 转成结构模型再生成字典。优势是离线、可追溯、能翻到某张表的每一次变更。但我很少拿它当主方案。线上库常有手工调整DDL 文件没跟着改增量脚本里只有 ALTER 没有完整建表语句也拼不出全貌。解析出来表面完整一对比线上全是差异反而误导。所以 DDL 解析适合做变更历史回顾线上结构唯一事实还是应该来自系统表采集。2.4 NC/T 老库的现实没有说明书时先建基线再补注释搜索 nc数据字典、t数据字典 的人大多是在实施或运维用友 NC、畅捷通 T面对的是几 GB 的数据库没有配套表结构说明书。网上流传的碎片字典不能直接抄——版本不同、行业包不同表结构差出几百张表都有可能。我从老 ERP 项目里总结的起步方法是把你手上这个库当唯一事实先用系统表做全量采集按模块前缀粗分类建立一份基线接着让实施顾问在基线上补业务注释反复两轮以后这份带注释的元数据才有资格叫数据字典。关键点是基线必须可重复生成每次重跑都稳定的脚本配合固定的连接参数和过滤规则才能防止今天导出一份、明天导出一份对不上。老系统没有文档已经是事实工具要做的不是硬补一篇文档而是把事实抓回来。实现路线数据来源优点主要限制适合场景JDBC 元数据解析现成工具/直连跨库、上手快定制弱、黑匣子临时摸底系统表查询information_schema/sys可控、易集成需权限、注释要人工补自研交付级字典DDL 解析版本库脚本离线、可回看易与线上漂移变更历史回顾运维平台导出数据中台/元数据平台自带血缘和权限绑定平台已有成熟平台的企业3. 用 Python 自建数据字典工具采集、补注、导出 Markdown 的完整脚本路线定了就动手。下面这套脚本我从工作早期一直在维护核心就三件事从 information_schema 拿全量字段合并人工注释渲染成 Markdown 和变更清单。它不依赖任何重型框架一个 Python 文件加一个 PyMySQL 就能跑。3.1 第一步连接 MySQL从 information_schema 拉全量表字段# -*- coding: utf-8 -*- # 数据字典工具读取表与字段元数据输出 JSON 快照 import pymysql import json import re import datetime db_config { host: 127.0.0.1, port: 3306, user: dict_reader, # 只读账号只授 SELECT password: change_me, charset: utf8mb4, # 防止中文注释乱码 read_timeout: 30, connect_timeout: 10, } target_schema erp_db # 要生成字典的库名 conn pymysql.connect(**db_config) cur conn.cursor()连接参数里charset 用 utf8mb4 是血泪经验老库中文注释能不能读全靠它read_timeout 给你兜底几千张表查询时不会让脚本无限期挂住。账号只授 SELECT不要用业务账号字典工具做的是只读采集权限越窄越不会在生产环境留后患。# 第一步拿表清单 cur.execute( SELECT table_name, table_comment, engine, table_rows FROM information_schema.tables WHERE table_schema %s AND table_type BASE TABLE ORDER BY table_name, (target_schema,), ) tables_meta {row[0]: {comment: row[1], engine: row[2], rows: row[3]} for row in cur.fetchall()} # 第二步一次 JOIN 拿全量字段避免每张表查一次 col_sql SELECT t.table_name, c.column_name, c.column_type, c.is_nullable, c.column_key, c.column_comment, c.ordinal_position FROM information_schema.tables t JOIN information_schema.columns c ON c.table_schema t.table_schema AND c.table_name t.table_name WHERE t.table_schema %s AND t.table_type BASE TABLE ORDER BY t.table_name, c.ordinal_position cur.execute(col_sql, (target_schema,)) rows cur.fetchall()第一条 SQL 拿表清单第二条 SQL 一次 JOIN 拿字段。早期版本我是每张表查一次列信息结果 T 账套两千多张表脚本跑了十几分钟改成 JOIN 以后全量采集基本秒级。注意 col_sql 里用 information_schema.tables 过滤 table_type否则会把视图也收进字典。# 组装 JSON 快照 meta { schema: target_schema, generated_at: datetime.datetime.now().isoformat(timespecseconds), tables: {}, } for table_name, col_name, col_type, is_nullable, col_key, col_comment, ord_pos in rows: meta[tables].setdefault(table_name, { comment: tables_meta.get(table_name, {}).get(comment, ), columns: [], }) meta[tables][table_name][columns].append({ name: col_name, type: re.sub(r\(\d\)$, , col_type), # int(11) 归一成 int nullable: is_nullable YES, key: col_key, comment: col_comment, ordinal: ord_pos, }) with open(dict_snapshot.json, w, encodingutf-8) as f: json.dump(meta, f, ensure_asciiFalse, indent2)setdefault 的写法是为了按表名分桶ordinal_position 保留下来Markdown 渲染时字段顺序才不会乱。类型归一化要解释一下MySQL 5.7 的 column_type 返回 int(11)8.0 直接返回 int正则只去掉纯整数括号decimal(10,2) 不会被动到。这个归一化不做后面 diff 会报出一堆伪变更。3.2 第二步人工注释层独立于自动元数据老 ERP 库的 COMMENT 为空是常态人工补注释又不能逼业务顾问改 Python。我采用的方式是单独维护 human_notes.jsonkey 是表名value 里放表注释和字段注释。脚本每次重跑时自动读取合并逻辑是人工注释有值就覆盖系统注释没有就保留系统注释下一次重跑不会被清掉。# human_notes.json 结构示例 # { # so_head: { # table_comment: 销售订单主表, # columns: { # id: 主键, # order_no: 订单号, # cust_id: 客户档案主键 # } # } # } with open(human_notes.json, encodingutf-8) as f: notes json.load(f) for table_name, table_meta in meta[tables].items(): note notes.get(table_name, {}) if note.get(table_comment): table_meta[comment] note[table_comment] for col in table_meta[columns]: col_text note.get(columns, {}).get(col[name], ) if col_text: col[comment] col_text有的顾问不看 JSON我会顺手加一个 CSV 导入路径格式固定为 table_name,column_name,comment 三列脚本同时读 JSON 和 CSV后读的覆盖先读的。原则只有一个人工注释和自动元数据必须分开存绝不能混在同一个结构里直接覆盖源库。字典工具追求的是可重跑不能把人的手写结果变成黑匣子。3.3 第三步渲染成 Markdown一表一节避免大文件卡死Markdown 渲染没什么玄学重点是体积控制。一表一个小节只保留字段名、类型、可空、键、注释五列。老库注释里可能有竖线和换行Markdown 表格会被截断渲染前统一替换。def render_markdown(meta, output_path数据字典.md): lines [f# {meta[schema]} 数据字典, ] for table_name, tbl in meta[tables].items(): comment re.sub(r[|\n\r], , tbl.get(comment, )).strip() lines.append(f## {table_name} {comment}) lines.append() lines.append(| 字段 | 类型 | 空 | 键 | 注释 |) lines.append(|---|---|---|---|---|) for col in tbl[columns]: col_comment re.sub(r[|\n\r], , col.get(comment, )).strip() lines.append( f| {col[name]} | {col[type]} | f{Y if col[nullable] else N} | f{col[key] or } | {col_comment} | ) lines.append() with open(output_path, w, encodingutf-8) as f: f.write(\n.join(lines))这里我一般直接写单文件几百张表以内打开很流畅如果表数超过三千改成按模块拆分多个 md否则编辑器渲染也会卡。每张表的字段等同一次目录摘要人查起来比去数据库客户端敲 DESC 快得多。3.4 第四步两次快照对比输出结构变更清单字典有没有用全看 diff。老快照和新快照对比时我只输出三类变更新增字段、删除字段、类型变化。类型变化判断基于 3.1 里已经归一化的 typeint 对 int 不会误报。字段重命名会表现为删除加新增人工一看就明白是改名不是危险变更。# 新快照 vs 旧快照输出 add/drop/type change def load_snapshot(path): with open(path, encodingutf-8) as f: return json.load(f) def col_map(snapshot): result {} for tname, tbl in snapshot[tables].items(): for col in tbl[columns]: result[(tname, col[name])] col return result old load_snapshot(dict_snapshot.json) new load_snapshot(dict_snapshot.new.json) old_cols, new_cols col_map(old), col_map(new) changes [] for key in sorted(set(new_cols) - set(old_cols)): changes.append(f新增字段 {key[0]}.{key[1]}: {new_cols[key][type]}) for key in sorted(set(old_cols) - set(new_cols)): changes.append(f删除字段 {key[0]}.{key[1]}: {old_cols[key][type]}) for key in sorted(set(old_cols) set(new_cols)): if old_cols[key][type] ! new_cols[key][type]: changes.append(f类型变化 {key[0]}.{key[1]}: f{old_cols[key][type]} - {new_cols[key][type]}) with open(变更清单.txt, w, encodingutf-8) as f: f.write(\n.join(changes))注释变化不参与自动 diff因为注释属于治理范围不需要阻断发版。如果把所有注释变更都算差异日志表一加注释整份变更清单全是噪音团队很快就没人看。变更清单的输出要有文件名这样后面接 CI 或者 pre-commit 时拿文本断言就行。3.5 参数速查连接、超时、过滤和输出参数推荐取值作用charsetutf8mb4防止中文注释乱码connect_timeout10连接失败快速返回read_timeout30防止慢查询拖死脚本target_schema单库名避免多库结果互相污染exclude_tablestmp_%、bak_%、%_log过滤临时和历史表include_tablesbd_%、pu_%、so_%只保留 ERP 核心模块output_formatmarkdowncsv兼顾阅读和二次处理参数尽量放 config.json不要让业务顾问改代码。我一般把目标库、白名单、黑名单、输出路径全部抽到配置文件脚本只读配置。换账套、换环境时改配置即可不用动一行代码。4. 数据字典生成的 5 个常见问题排查连接、乱码、性能与字典漂移脚本写出来不踩几个坑是不完整的。下面五条都来自我做过实施交付的真实记录按现象、原因、处理三段展开可以直接当排查手册用。4.1 问题一账号能登录却一张业务表都看不到现象用自定义账号连上去pymysql 已经连接成功但跑完元数据后 tables 是空的。原因有两个。一是权限没到位MySQL 里 information_schema 的表行可见性受底层表权限控制业务库没有 SELECT元数据查询结果就是空的。二是连错实例T 项目常见应用库和账套库分在不同实例连到系统库自然看不到业务表。排查顺序固定先 SHOW GRANTS 看账号权限再查 information_schema.schemata 看它能看到哪些库两句话就能定位问题不用进服务器翻配置。-- 给只读账号补业务库权限 GRANT SELECT ON erp_db.* TO dict_reader%; FLUSH PRIVILEGES; -- 检查当前账号权限确认能看到哪些 schema SHOW GRANTS; SELECT schema_name FROM information_schema.schemata;注意 GRANT 之后新会话才会生效Python 脚本要重连。如果是数据库账号列表里只有 % 没有 localhost也会出现本机连接成功但无权限的怪事把两个 host 都授权即可。4.2 问题二表注释和字段注释导出后乱码现象汉字变成问号或者一堆乱码像 “馔 这种形态。原因主要两处连接串 charset 没指定 utf8mb4元数据在客户端按 latin1 解码或者源库表字符集是 gbkinformation_schema 里的注释是 UTF-8两层编码混在一起排查到后面像玄学。处理先看库级字符集SELECT DEFAULT_CHARACTER_SET_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME erp_db;如果是 gbk连接时先试 utf8mb4不行再读出来用bytes(comment.encode(latin1)).decode(gbk)兜底最彻底的还是把表字符集改成 utf8mb4。若注释取出来为空先别急着转编码看看建表语句里有没有写 COMMENT——没写就是真没有补注释不是工具能自动完成的事。4.3 问题三字段类型对不上int 与 int(11) 的误会现象一次升级后 diff 冒出来几百条类型变化全部是 int(11) 变成 int实际什么都没改。原因是 MySQL 8.0 把显示宽度移除了5.7 的 column_type 里还留着 int(11)。处理方式我已经放在采集阶段re.sub(r\(\d\)$, , column_type)。注意不能把 decimal(10,2) 一块儿去掉正则只处理不带逗号的整数宽度。遇到所有类型判断必须基于归一化后的值否则变更清单的准确性无从谈起。4.4 问题四上千张表的字典导出直接卡死现象NC/T 表数量过两千脚本跑了十几分钟导出的 Excel 几十 MB滚动都卡。原因早期脚本采用每张表查一次的 N1 模式把几万行字段一次性堆在内存里最后才写 Office 文件Excel 行数超过几万后渲染是灾难。处理分两步。查询改为一次 JOIN 拉全量写入改为流式边读边写 CSV 或 Markdown# 流式写入 CSV避免把所有数据堆在内存里 import csv with open(字典_全量.csv, w, newline, encodingutf-8-sig) as f: writer csv.writer(f) writer.writerow([表名, 字段, 类型, 注释]) for row in gen_rows(): # gen_rows 每次只吐一行 writer.writerow(row)编码用 utf-8-sig这是给 Excel 用户准备的血泪经验不加 BOMExcel 双击打开中文乱码。选 xlsx 的话用 xlsxwriter 的 write-only 模式按行写不要 one-shot 列表。4.5 问题五字典发布后没人维护线上结构悄悄变了现象字典在验收时新鲜出炉三个月后开发反馈字段找不到查线上才发现上线时加过列字典没人同步。原因是字典和线上库之间没有对账机制。数据字典工具能提供的唯一后悔药是恢复一份事实快照没有快照就没有办法证明结构和三个月前哪里不一样。处理是建立对账闭环字典文件进 Git采集脚本进定时任务变更清单留档。真正的产出物是变更清单不是 Markdown 文档——文档是人读的diff 是流程用的。这也是下一章要做增量快照和提交前校验的原因。5. 让字典不烂尾增量快照、白名单过滤和提交前校验工具跑通只是起点半年后还有人信这份字典才算达标。我维护字典的方式是把它当代码资产对待能对比、能过滤、能自动校验。5.1 增量快照用表级指纹代替全量扫描几千张表每次全量扫虽然能接受但没必要。InnoDB 的 update_time 不稳定有些引擎还返回 NULL不能拿它判断结构是否变化。我维护表级指纹某张表的字段列表、类型、可空、键名拼成 JSON 字符串做 SHA1只有指纹变化才重新采集列。def table_fingerprint(meta, table_name): cols meta[tables][table_name][columns] payload json.dumps( [(c[name], c[type], c[nullable], c[key]) for c in cols], ensure_asciiFalse, sort_keysTrue, ) return hashlib.sha1(payload.encode(utf-8)).hexdigest()指纹里不含注释和行数避免把数据量变化误报成结构变更。两版快照对比时先比表级指纹把候选表筛到个位数再比字段省下来的时间在 CI 里非常值钱。你可以把每次快照的表指纹单独存成一个 summary.json扫描时只开一次连接取指纹和行数比对过后再决定要不要深挖某张表。5.2 白名单与黑名单把临时表、日志表、备份表挡在字典外老 ERP 库里表名很乱日期后缀、bak、tmp、ths_ 全混在一起。全量收录的字典噪音太大顾问不想看。过滤规则要进配置给两个数组 include 和 excludeexclude 优先include 为空表示不过滤业务表。{ include_tables: [bd_%, pu_%, so_%, sa_%, ar_%, ap_%], exclude_tables: [tmp_%, bak_%, temp_%, %_log, ths_%] }这个配置要让顾问和 DBA 一起过两轮。我就翻过车把 ths_ 前缀当临时表过滤了结果它是 T 某个版本的留存模块几十张业务表直接消失。过滤规则的坑不在正则写法在于那份表前缀清单本身有没有人读懂业务。include 和 exclude 不要只配一个后续新加模块时很容易漏。5.3 提交前校验把字典一致性做成 pre-commit 钩子如果开发流程在 Git 上最简单的兜底是 pre-commit 钩子。提交前跑一次采集如果 diff 发现危险变更——删除字段、主键变化、类型收缩——直接拦截。这里只拦截危险变更不拦新增字段避免误杀太多让团队绕过钩子。#!/bin/bash # .git/hooks/pre-commit提交前检查字典与线上库的一致性 python dict_tool.py --dump /tmp/dict_new.json python dict_tool.py --diff /tmp/dict_new.json dict_snapshot.json \ --fatal column_drop,primary_key,type_shrink if [ $? -ne 0 ]; then echo 检测到数据字典与线上库不一致请先同步字典再提交。 exit 1 fi没钩子的环境可以把它放进 CI发版前跑一个 job采集线上快照与仓库基线对比把变更说明输出到构建日志。注意校验失败时输出必须明确指出差异来源否则同事只会觉得校验器在为难人。钩子里我一般还会做一层保护本机连不上库时跳过校验但打印一行警告避免开发本地断网就无法提交代码。6. 一个逆向技巧用列名归一化给旧 ERP 库生成字段血缘草稿字典能保持新鲜以后最常被问到的就是这些表之间怎么串。老 ERP 库大多没有外键ER 图画不出来但有个取巧办法列名归一化。把常见字段名映射到业务实体比如 cust_id 和 pk_customer 都归到 customerorder_no 和 pk_order 都归到 order然后统计每个实体在哪些表出现就能得到候选血缘关系。# 候选血缘字段名 - 业务实体按实际库修正 entity_of { cust_id: customer, customer_id: customer, pk_customer: customer, vendor_id: supplier, supplier_id: supplier, order_id: order, order_no: order, pk_order: order, } def table_entities(columns): return sorted({entity_of[c[name]] for c in columns if c[name] in entity_of})跑完把每个表命中的实体写回字典输出一张“customer 相关字段出现在哪些表”的清单。这份清单不要直接当血缘图用而是当成访谈提纲拿给业务顾问确认哪些是真关联哪些只是同名没有业务关系。我在这上面吃过亏曾经把机器猜的关系直接写进交付文档被顾问连续纠正了十几个后来一律标注“草稿”只作为访谈起点。字段血缘不依赖外键也不依赖数据抽样成本很低特别适合 NC/T 这类没有设计文档的老库。它不会替你把关联关系自动建好但能把顾问访谈范围从几百张表缩小到几十个实体效率提升是实打实的。整理数据字典这条路没有终点库表一直在变所以要习惯把工具当成长期维护的对象而不是一次性交付物。希望这个思路帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。