news 2026/9/7 19:32:55

MongoDB迁移PostgreSQL实战:协议兼容与JSONB性能对比

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MongoDB迁移PostgreSQL实战:协议兼容与JSONB性能对比

去年帮一个做内容平台的团队做过一次文档数据库改造,他们的核心库跑在 MongoDB 上,承载了几千万条业务文档,每天查询量上亿。当时换库的压力不是“要不要做”,而是“怎么在应用几乎不改代码的前提下把底层换掉”——既要降低迁移风险,又要在性能上有账可算。最后我们走的路线,是一套基于协议级兼容的方案:应用继续用 MongoDB 驱动说话,后端落到 PostgreSQL 的 JSONB 引擎上,然后用性能对比数据来验证收益。今天这篇就把整个过程中的协议兼容原理、JSONB 与 BSON 的差异、迁移实操步骤和性能测试结果全部拆开聊一遍。

这篇内容适合谁?一类是正在考虑把 MongoDB 迁移到 PostgreSQL、但担心应用改造成本太大的团队;另一类是对 Jsonb 性能上限没底、想拿真实测试数据做决策的人。也包括单纯想搞懂“文档数据库迁移到底动了哪些器官”的后端工程师。我会尽量用做过的实际案例讲原理,不整虚的。

1. 文档数据库迁移场景与协议兼容层原理

1.1 为什么会出现“MongoDB 协议级兼容”这种方案

先聊清楚需求是怎么来的。大部分团队从 MongoDB 迁走,原因无非三类:成本、团队技术栈、合规要求。MongoDB 的商业版授权不便宜,社区版的运维门槛又不低;而 PostgreSQL 的生态更完整,企业里会的人多,控制面也更成熟。

但问题在于,业务代码里已经写满了 MongoCollection、MongoCursor、Document 这一套抽象,还有大量直接投放的 JSON 查询语句、聚合管道、 $push / $unset / $elemMatch 这些操作。如果换库意味着每个仓库都要重写数据访问层,那项目基本凉一半。

协议级兼容要解决的就是这个事:保留 MongoDB wire protocol 这一层对外形态,让客户端驱动认为自己在跟一个真 MongoDB 通信,可后端存储却换成了 PostgreSQL JSONB。具体实现上,通常是起一个兼容服务端,解析 MongoDB 驱动发来的 opcode 或 OP_MSG 报文,把查询语义转换成 SQL 打到 PostgreSQL。

这一步转换质量直接决定了整个方案好不好用。文本协议好解析,难的是把 BSON 文档、嵌套数组、聚合管道的语义完整映射到 SQL。做得粗糙的兼容层只处理 find、insert、update,遇到聚合管道就“半支持”,这种方案上线就是给自己挖坑。

1.2 兼容层到底替你做了什么

只说概念太虚,拆细一点。一次 MongoDB 操作,兼容层要做的核心动作是三层:

  • 协议解析:识别客户端驱动版本、认证方式(SCRAM-SHA-256 等)、读写偏好,把 BSON 二进制流还原成内存里的文档对象。
  • 语义重写:把 MongoDB 的查询条件(filter)、排序、聚合阶段,改写为 PostgreSQL 可执行的 SQL 语句,尤其是 JSONB 字段上的表达式和索引路径。
  • 结果集逆转换:把 PostgreSQL 查出来的行记录再拼装回 BSON 文档,保持驱动端看到的数据结构和类型一致。

这里面最容易被低估的是类型映射。MongoDB 的 ObjectId、日期、Binary、正则表达式,和 PostgreSQL 的类型不是一一对应的。ObjectId 最稳妥的做法是转成 char(24) 或 uuid,但排序规则会发生微妙变化;日期要处理毫秒精度和时区问题;BSON 的 32 位整数、64 位整数、Double 在 JSONB 里存成数字后,查询时可能因为类型不同命中不了索引。

实测中,兼容层还会承担一部分“谎言维护”的工作:比如 MongoDB 驱动在连接时会发 ping、读取 server status、检查写关注(write concern),兼容层必须返回一套看起来非常真实的结果,否则高版本驱动会直接拒绝连接。像是 getLastError 这种老协议命令,也要兼容处理。

注意:协议级兼容不是免费的。每一层转换都会引入延迟和 CPU 开销,如果兼容层本身写得不高效,最终性能可能比原生 MongoDB 差很多,这点在下文性能对比部分会专门验证。

2. JSONB 与 BSON 的底层差异是性能分水岭

2.1 存储格式与索引结构的不同

很多人以为 JSONB 就是把 JSON 字符串塞进 PostgreSQL 字段里,这是最大的误解。JSONB 的 B 是 Binary,内部是以一种解析好的二进制格式存储的,键会被排序去重,数字会被规范化。而 MongoDB 的 BSON 则是另一种二进制序列化,保留文档的原始层次,但不做键排序。

差异带来的第一个结果是空间占用。相同内容下,BSON 因为类型前缀和长度前缀,通常比 JSONB 更紧凑;JSONB 为了支持高频键查找,把键名做了字典化存储,文档嵌套层次越深,JSONB 的体积膨胀越明显。

第二个差异在索引。MongoDB 对文档字段建索引用的是 B-Tree 或多键索引,字段路径可以直接指向文档中的某个叶子节点。PostgreSQL 对 JSONB 的加速查询主要靠 GIN 索引,配合操作符类(jsonb_ops、jsonb_path_ops)生成倒排项。具体来说:

  • jsonb_ops 索引会生成每一个键值对的条目,适合处理存在性查询和单键查询,但索引体积大。
  • jsonb_path_ops 只生成完整路径的哈希,索引体积小,但对存在性查询支持有限,而且无法支持某些跨层级的表达式查询。

这意味着白从上往下看似乎都能查,但查询计划差别非常大。MongoDB 对嵌套字段建索引后,只访问需要的分支即可;PostgreSQL 的 GIN 索引则是把整个 JSONB 拆成条目,目标字段越大、嵌套越深,索引的过滤精度就越差,必须回表做精确匹配。

如果你在建表时能把频繁查询的字段抽成独立的普通列,这套体系会好很多。协议兼容层对这种“字段上提”的优化支持程度,决定了你在查询性能上有多大的提升空间。

2.2 操作语义差异:从数组更新到文档叠加

MongoDB 的文档模型里,最被开发者依赖的是原地更新能力。比如 $inc 一个计数器、$push 往数组里塞元素、$unset 删掉一个字段,都是一次原子操作,不需要客户端先读后写。这在 JSONB 引擎里却是个坎。

PostgreSQL 的 JSONB 不提供类似 $push 的原生操作符,更新一个数组字段需要用 jsonb_insert 或 jsonb_set 拼接出新文档再整体写回。拼写过程并不复杂,但问题在于并发控制:两个请求同时 push,如果都基于同一份旧文档构造新文档,后提交的会把先提交的覆盖掉。这在 MongoDB 里因为文档锁和原子更新机制会好很多,到 JSONB 就得靠显式行锁(SELECT FOR UPDATE)或者乐观锁版本号兜底。

我建议的做法是,协议兼容层在收到 $push 时,自动改写为“带条件更新的 SQL 子查询”:

UPDATE doc_table t SET data = jsonb_set(t.data, '{tags}', t.data->'tags' || '["new_item"]') WHERE id = $1 AND NOT t.data->'tags' @> '["new_item"]';

同样的问题也出现在嵌套对象更新上。MongoDB 的 $set 支持点分割路径,比如 { "profile.address.city": "Beijing" },这非常直观。到 JSONB 里,你需要把路径拆解成每一层的键存在性检查,再调用 jsonb_set 逐层重建。层级越深,查询表达式越长,优化器也很难对中间结果做合理的估算。

这类语义差异不会在功能测试阶段暴露问题,但一旦上了生产并发,覆盖率立刻出现。这也是我为什么坚持要做一套自动化语义测试用例,把 MongoDB 端的增删改查跑一遍,记录结果集,再到兼容层重放比对,而不是靠人肉点点点。

2.3 聚合下推与查询改写的天花板

MongoDB 聚合框架(aggregate)是它的核心卖点。$lookup 可以关联集合,$group 可以做分组,$unwind 可以把数组拆成多行,$project 可以重排字段。协议兼容层接到这些管道后,理想情况是尽可能下推给 PostgreSQL 执行,否则就要把数据拉到兼容层内存里自己算——那样性能和内存都扛不住。

从实现上讲,以下聚合阶段目前能相对优雅地下推:

  • $match:映射为 WHERE 条件,最简单也最好优化。
  • $sort:映射为 ORDER BY,前提是排序字段能被 PostgreSQL 索引覆盖。
  • $limit / $skip:映射为 LIMIT / OFFSET。
  • $group:映射为 GROUP BY,但只支持基础聚合操作符(SUM、AVG、MIN、MAX)。
  • $project:映射为 SELECT 列表中的字段裁剪。

凡是涉及文档内数组展开或任意 JS 表达式的阶段,基本都是兼容层的噩耗。$unwind 映射成 PostgreSQL 的 jsonb_array_elements 函数展开是可行的,但这会极大地改变行数估算,性能容易失控。$lookup 如果关联键藏在 JSONB 内部,就没法直接用普通 JOIN,得先拆字段再关联,代价非常大。

我在测试中遇到最惨烈的场景是一次 $lookup 关联 + $unwind + $group 三连的聚合任务,在原生 MongoDB 上跑 3 秒,在兼容层上跑了 40 多秒——因为 $unwind 后的中间行数被严重放大,优化器完全没有意识到 JSONB 展开后的基数爆炸。

经验之谈:接入协议级兼容前,先对业务里最重的 20 条聚合查询做语义分析和下推评估。如果发现到处都是 $lookup 和 $unwind,那就别指望兼容层能兜底,老老实实做一部分应用层重写,把最重的聚合改成物化视图或独立表,效果会好得多。

3. 迁移实操拆解:从评估到切换的完整链路

3.1 迁移前评估:先给存量数据做体检

动手迁移之前,我强烈建议先花几天时间做数据体检。这不是走流程,而是为了规避三类风险:数据量级超出预期、字段结构混乱导致类型映射失败、冷数据占比过高拖慢全量迁移。

体检内容包括四部分:

  • 库表清单与体量统计:通过 db.stats() 和每个 collection 的 count、avgObjSize 拿到基础数据,确定哪些集合是核心热数据,哪些是日志型冷数据。
  • 嵌套深度与字段类型分布:抽样分析文档的最大嵌套深度、数组使用频率、字段值的类型分布(字符串、数字、嵌套对象、Null、数组)。重点看有没有字段在不同文档里出现不同类型,这是 JSONB 类型映射最头疼的问题。
  • 查询模式采集:开启 profiling 收集慢查询和日常查询语句,分析哪些字段被高频过滤和排序,方便后续设计索引和字段上提方案。
  • 依赖与周边梳理:确认有没有依赖 MongoDB 地理索引、全文检索、TTL 索引、Change Stream 的特性,这些在 JSONB 引擎上需要单独做替代方案。

做完体检后,我会输出一份“集合映射建议表”,标明每个集合是“直接转 JSONB 表”还是“核心字段上提 + 剩余内容入 JSONB”。这个决策非常关键,直接决定了迁移后的查询性能。

3.2 集合映射与 JSONB 表结构设计

不是所有 MongoDB 集合都适合原样平移到 JSONB 表。我一般按业务特征分成三类:

第一类:关系型特征明显的数据(用户、订单、商品)。这类数据通常有固定的查询维度,比如按用户 ID、订单号查。我建议把 ID、创建时间、状态等关键字段提升为普通列,并建好 B-Tree 索引,其余扩展字段放进 JSONB 列。这样既能保留 MongoDB 的灵活,又能获得 PostgreSQL 的查询性能。

第二类:纯文档型数据(配置信息、日志记录、动态表单内容)。这类数据查询条件不固定,通常全量扫描或者简单条件过滤,直接整包放进 JSONB 列即可。

第三类:超大数组和嵌套深度极高的文档。这类数据需要特别小心。JSONB 单行最大支持 1GB(实际受到 TOAST 策略影响),但嵌套更新和展开计算代价很高。建议拆成“主表 + 子表”的结构,数组部分平移到关联子表,主表只保留文档主体。

表结构设计的时候,还要注意主键策略。MongoDB 的 _id 如果是 ObjectId,建议转换为 char(24) 或 varchar(24) 保存;如果业务已经使用 UUID 或业务主键,保持原样即可。所有 JSONB 字段的默认值建议设为 '{}',避免 NULL 带来的索引和查询语义混乱。

分配字段上提时需要特别留意数组字段。数组字段如果上提为 PostgreSQL 数组类型,兼容层操作会方便很多;但如果上提后又想用 GIN 索引,就需要安装 btree_gin 扩展。我习惯的做法是:高频查询数组字段才上提,低频直接留在 JSONB 内部。

3.3 数据迁移三件套:全量、增量、校验

数据迁移本身我分成三步走:全量导出、增量追平、校验。

全量导出可以用 MongoDB 自带的 mongodump 导成 BSON 归档文件,也可以写脚本用 mongoexport 逐集合导出 JSON 文件。更推荐的是用连接器框架写一个迁移程序,直接用原生驱动读取 MongoDB,然后批量写入 PostgreSQL,因为这样可以在读的过程中完成类型转换和字段映射,减少中间态文件管理。

我实际用的方式是双轨同步:用一个自研的 Python 迁移脚本,通过 pymongo 读取集合的每个文档,经过转换函数生成 PostgreSQL 的 JSONB 值,再通过 COPY 协议批量导入到目标表。小数据集无所谓,大数据集一定要用 COPY 而不是逐条 INSERT,写入性能至少差一个数量级。

增量追平听起来简单,做起来麻烦。MongoDB 侧可以用 Change Stream 监听数据变更,把变更流转发到 PostgreSQL。这里有个坑:Change Stream 需要 MongoDB 集群开启副本集,单机版跑不了。另外,Change Stream 的事件里包含完整文档(updateLookup),转发时要保证幂等,因为网络抖动可能导致重复事件。

校验是整个迁移成败的关键,不能只比对记录数。我通常会做三层校验:

  • 计数校验:每个集合的行数一致。
  • 哈希校验:对每条记录的主键和核心字段生成哈希值,做全量比对。
  • 抽样语义校验:从源库抽取热点查询语句和聚合查询,在目标库重放,比对结果集结构、字段类型和数量。

三层都过了,才敢放心走切换流程。

3.4 应用层改造与切流回滚方案

即使有协议级兼容,完全不改应用是不现实的。至少要做几件事:

  • 驱动版本调整:某些 MongoDB 驱动版本包含了兼容层尚未实现的特性,建议锁定到兼容层官方验证过的版本区间。
  • 连接配置调整:把 MongoDB 的 URI 指向兼容服务地址,设置合适的连接池大小(通常比原生 MongoDB 略大,因为单次请求耗时变长)。
  • 错误处理兼容:MongoDB 的错误码、写关注异常、游标超时行为在兼容层下可能不同,需要提前跑一遍故障演练。

切流方案我建议用灰度和闪断结合的方式。第一阶段让 5% 的读流量打到新库,比对监控指标;第二阶段切 50%;第三阶段在低峰期做一次闪断切换,完成写流量迁移。整个过程必须有兜底回滚预案:把协议兼容层视作一个独立服务,回滚只需要把应用连接配置切回原 MongoDB 地址,同时暂停增量同步任务即可。

切流前一定要演练三遍回滚。数据库迁移常见的翻车现场,就是切流后发现性能不达标想回滚,结果增量通道已经断了很久,旧库已经落后太多。保留至少一周的增量同步窗口,确认新库稳定后再下线同步任务,这个窗口不能省。

4. 性能深度对比:同数据、同操作序列的实测记录

4.1 测试环境与方法设计

性能对比最忌讳“裸奔”。同样一套数据,在 MongoDB 上跑出的数字和 PostgreSQL JSONB 上跑出的数字,如果硬件、数据集、索引策略不一致,对比就没有参考意义。

我当时的测试环境是两台同规格裸金属服务器,CPU 型号和核数一致,内存 128GB,数据盘都是 NVMe SSD。MongoDB 使用 6.0.5 版本,WiredTiger 存储引擎;PostgreSQL 使用 16.1 版本,JSONB 字段使用 GIN 索引。数据集统一构造为 2000 万条文档,平均文档大小约 4KB,包含嵌套对象和数组字段,文档结构参考了真实业务的内容标签、用户画像、扩展属性三块。

压测工具选择上,我用了自研的多线程负载脚本,分别对两个库执行相同的操作序列。每个操作序列都包含五类任务:单条点查、批量范围查询、条件计数、嵌套字段数组更新、聚合分组统计。为了排除缓存干扰,每轮压测前都会重启数据库进程并清空操作系统缓存。

需要特别说明的是,这个测试对比的不是“同一个查询语句在两个库上跑”,而是“同一份应用操作意图在两个库上各自被原生执行计划覆盖”。因为比对 SQL 没有意义,应用侧根本不需要写 SQL。

4.2 读写与更新场景的数字差异

先看点查。单条 _id 查询在 MongoDB 上延迟约 0.3 毫秒,兼容 JSONB 方案约 0.8 毫秒,差距不大。但如果查询条件是 JSONB 内的二级嵌套字段,MongoDB 因为有精准的多键索引,命中率很高,而 PostgreSQL 需要先通过 GIN 索引定位到候选文档再做精确匹配,延迟差距扩大到 3 到 5 倍。

再看写入。这是 JSONB 方案的明显短板。MongoDB 的写入路径短,更新文档时直接定位 BSON 文件位置即可。JSONB 每次写入都要序列化整个文档、更新索引、可能触发 TOAST 压缩。在我压测中,纯插入场景两者差距在 1.5 倍到 2 倍之间,而 JSONB 的字段越多、嵌套越深,差距越大。

更新场景是最惨烈的一组。MongoDB 的 $push 操作在 1ms 内完成,兼容层模拟同样的数组追加操作,需要读出整条文档、jsonb_set 拼接、写回、以及处理行锁竞争。并发从 10 提升到 100 时,MongoDB 更新吞吐保持平稳,兼容方案出现明显锁等待,更新延迟从 3ms 飙升到 30ms。

这里要强调,读多写少的业务场景,JSONB 性能完全可以接受;但写密集且涉及数组、嵌套更新的场景,就需要特别设计优化策略,比如把频繁更新的字段上提为普通列,或者在应用层做合并写缓冲。

我把这轮测试的典型数据整理成了表格,方便参考:

操作类型MongoDB 平均延迟JSONB 兼容层平均延迟差距
主键点查0.3ms0.8ms约2.7倍
二级嵌套字段查询1.0ms3.5ms约3.5倍
单条插入0.6ms1.2ms2倍
数组追加更新1.0ms4.5ms4.5倍
条件计数600ms420ms优 30%

4.3 聚合查询与排序分页的差距

聚合和排序是 JSONB 反超 MongoDB 的主要阵地。

MongoDB 的聚合框架虽然方便,但实现方式偏向解释执行。$group 和 $lookup 在数据量大时,经常出现内存瓶颈,2000 万数据量级的分组统计有时会触发 allowDiskUse,性能断崖式下跌。而 PostgreSQL 的优化器和执行引擎经过几十年打磨,对 GROUP BY、JOIN、排序的处理非常成熟,只要字段能被解析成普通列,性能优势就非常明显。

在一组按标签分组统计的测试里,MongoDB 跑完整耗时 6 秒,JSONB 方案只用了 2.1 秒。在排序场景,按创建时间倒序并分页拉取文档,MongoDB 在 2000 万数据上需要 2 秒以上,JSONB 方案通过 B-Tree 索引直接命中,耗时压到 500 毫秒以内。

但 JSONB 也不是无敌。当聚合涉及嵌套数组展开时,PostgreSQL 需要对 jsonb_array_elements 的中间结果做物化,行数估算偏差很大。举例来说,一个文档里有个 average 30 个元素的数组,展开后 2000 万文档会变成 6 亿中间行,排序或分组时内存瞬间打满,性能直接爆炸。

如果在兼容层上做聚合,最终耗时往往取决于兼容层有没有把聚合阶段完整下推。下推得越彻底,PostgreSQL 优化器越有机会做全局优化;遇到无法下推的 $unwind、$lookup,性能就只能靠兼容层进程的内存硬扛,结果通常非常难看。

5. 常见问题与排查技巧实录

5.1 中文全文检索失效

MongoDB 的文本索引对中文的支持依赖分词器,用起来虽然不算完美,但至少能直接搜。切换到 JSONB 后,如果使用 GIN 索引的默认操作符,中文分词几乎无效,只能按子串匹配,性能非常差。

解决思路不是在兼容层层面想办法,而是在应用层新增一个 tsvector 列,通过触发器在写入时同步生成词向量。查询时把 MongoDB 的 $text 语法转成 tsvector 的匹配条件,利用 GIN 索引正常加速。这个做法需要业务方接受一个事实:全文检索字段在 PostgreSQL 侧是冗余存储的。

不要指望协议兼容层自动帮你解决全文索引问题。MongoDB 文本索引的语义和 PostgreSQL 全文检索的语义本身就不等价,自动翻译能做到“能搜”,但很难做到“搜得准”,尤其是中文长词和同义词场景。

5.2 $elemMatch 与 jsonb_path_exists 语义不一致

这是我最想吐槽的一个坑。MongoDB 的 $elemMatch 用于匹配数组中至少一个元素满足所有条件,逻辑非常直接。兼容层如果实现得浅,会把 $elemMatch 改写成 JSONB 的 @> 存在性判断,看起来好像能出结果,但实际上两个条件的语义完全不等价。

比如查询数组字段中既包含“名称等于 A”又包含“价格大于 100”的文档。MongoDB 要求数组中同一个元素同时满足两个条件,而 @> 只要数组里有任意元素满足第一个条件、另一个元素满足第二个条件,就会返回真。这种差异在测试数据量小的时候根本发现不了,等上了生产就是奇怪的脏数据问题。

排查这类问题,需要把兼容层生成的 SQL 打印出来,逐条对照原始 MongoDB 查询条件做语义审查。必要时强制改写为 jsonb_path_exists 加路径通配符的方式,例如:

jsonb_path_exists(data, '$.items[*] ? (@.name == "A" && @.price > 100)')

这条语句才能最接近 $elemMatch 的语义。

5.3 写入性能骤降与 TOAST 高水位

迁移初期写入性能尚可,运行一周后写入越来越慢,这是我在实际项目中遇到的真实问题。排查后发现,罪魁祸首是 JSONB 大字段频繁更新导致 TOAST 表膨胀,表膨胀严重时,每一次写入都要扫描大量死元组,VACUUM 又跟不上生产节奏。

应对措施有两方面。短期做法是调高 autovacuum 频率,对相关表单独设置更激进的阈值参数,比如减少 autovacuum_vacuum_scale_factor 并增加 naptime。长期做法是优化写入模式:高频更新的小字段全部上提为普通列,JSONB 里只保留低频修改的冗余字段,让 TOAST 的写入次数降下来。

另外,PostgreSQL 的 JSONB 更新机制是整行写新版本,而不是原地修改。如果业务对写路径的要求极高,单纯依赖 JSONB 作为主存储并不是最优解。可以考虑用 PostgreSQL 的分区表把活跃数据和不活跃数据分开,或者对特定高频集合使用只读副本分流。

5.4 迁移校验阶段数据对不齐的排查思路

校验阶段最让人头大的是“源库和目标库记录数一致,但哈希比对大范围不一致”。第一次遇到时我也很懵,后来发现主要来源是类型精度差异。

MongoDB 的日期类型只精确到毫秒,PostgreSQL 的 timestamp 可以精确到微秒。如果迁移时没有统一做精度截断,目标库就会多出微秒位,导致哈希不一致。更重要的是,MongoDB 的数值在 BSON 中可能是 32 位整数、64 位整数或 Double,而 JSONB 数字类型只区分整数和小数,所以整数被映射回 JSONB 时可以保持一致,但浮点数的二进制表示在跨库转换中可能发生微小偏差。

解决方式是在迁移脚本里对所有数值和日期字段做显式归一化:日期统一截断到毫秒再写入,数值统一转成 Decimal 或整数后比较。校验时也要用相同的归一化规则做哈希,而不是拿原始字符串做拼接。

迁移校验还有一个独门技巧:不要只比对两个库,要让源库、目标库、中间格式(比如迁移脚本打出的 JSONL 文件)三方比对。中间格式出了问题,可以快速定位是读取阶段还是写入阶段出错,省去大量的重复排查时间。

最后说点个人体会

整套方案折腾下来,我的核心感受是:协议级兼容是“降低迁移启动门槛”的好东西,但永远不要把它当成万能黑盒。它能帮你平滑度过切换期,但无法替你承担所有数据模型差异带来的后果。真正决定长期性能的,依然是业务数据的结构设计,以及你在迁移过程中有没有认真做字段上提、索引规划、更新语义梳理这些脏活累活。

如果你正打算走这条路,我的建议是不要一上来就追求 100% 功能兼容,而是先挑一两个读多写少、查询模式简单的业务集合做试点,把兼容层、迁移脚本、校验工具全链路跑通,积累一批问题后再扩大范围。数据库迁移这种事,稳远比快重要。希望这篇实战记录能帮大家少踩几个坑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 19:32:44

Cloudflare Workers上运行Express API的CORS跨域配置实践

最近在给前端项目搭 API 服务,又是 CORS 问题把我卡住了。前端跑在 localhost:5173,后端接口部署在 Cloudflare Workers 上,浏览器直接报“has been blocked by cors policy: No Access-Control-Allow-Origin header is present”。这个报错你…

作者头像 李华
网站建设 2026/9/7 19:32:03

编程题练习30天与计算机英语翻译23天:双线打卡的成长复盘

有没有过这种经历:收藏夹里躺着几十篇“刷题攻略”,却连第一页题都没看完;背单词App打卡三百天,真拿到一份英文技术文档还是读得磕磕绊绊。我之前也这样,直到把“编程题练习”和“计算机英语翻译”拆成两条独立的每日打…

作者头像 李华
网站建设 2026/9/7 19:31:57

网络安全从业人员必收藏的几个网站!

1 网安类知识库 (1)看雪知识库 https://www.kanxue.com/chm.htm (2)白阁文库 白阁文库是白泽Sec团队维护的一个漏洞POC和EXP披露以及漏洞复现的开源项目,欢迎各位白帽子访问白阁文库并提出宝贵建议。 https://wik…

作者头像 李华
网站建设 2026/9/7 19:30:21

太赫兹UM-MIMO与IRS混合信道估计:球面波与平面波联合稀疏恢复

最近这个太赫兹集成UM-MIMO和IRS系统的混合信道估计项目在仿真圈子里讨论度挺高,版本编号都出到14942期了。我也照着思路自己完整跑了一遍,把代码结构、信道建模、字典设计这些核心环节都重新捋清楚了。这个项目本质上不是单纯调一个函数就能出结果的dem…

作者头像 李华
网站建设 2026/9/7 19:29:21

css实现图片大小自适应

方法一:css的background属性来设置背景图知识点总结background的属性有以下这些: background-colorbackground-positionbackground-sizebackground-repeatbackground-originbackground-clipbackground-attachmentbackground-image1.background-color就不…

作者头像 李华