)
前言随着政企信创系统业务量快速增长单库单表逐渐触达性能瓶颈分库分表成为很多核心系统的必然选择。但国产数据库人大金仓、达梦等搭配 ShardingSphere/MyCat 等中间件的组合远比 MySQL 生态更容易踩坑SQL 解析失效、方言不兼容、事务回滚失败、主键冲突、扩容困难…… 很多项目上线后故障频发反而不如单库稳定。本文基于10 政务 / 国企核心系统分库分表落地经验从架构选型、SQL 兼容、主键事务、运维扩容、国产化特性五个维度整理了 24 个 90% 项目都会犯的经典错误每个坑都附现象、根因与生产级解决方案帮你避开绝大多数弯路。一、适用范围底层数据库人大金仓 KingbaseES V9、达梦 DM8/DM9分片中间件ShardingSphere-JDBC 5.x、MyCat 2.x业务场景政务审批、国企订单、民生服务等 TB 级数据量系统适用人群信创架构师、后端开发、DBA、项目技术负责人 一、架构选型与分片设计类坑前期错了后期改不了这类错误属于 “先天缺陷”上线后再改成本极高甚至需要推倒重来。坑 1盲目上分片单库能扛硬拆分现象几十万数据量就上分库分表复杂度翻倍性能反而不如单库运维成本飙升。根因把分库分表当银弹忽略了国产数据库单库支撑能力 —— 金仓 / 达梦单库 5000 万行、1TB 数据完全可以通过索引、分区表优化满足性能。解决方案优先用分区表按时间 / 区域解决单表性能问题分区表对业务零侵入单库 TPS 持续超过 2000、单表数据量超 5000 万且持续高速增长再考虑分库分表坑 2分片键选错数据分布严重不均现象某几个分库 CPU、磁盘占用是其他库的 5~10 倍热点库成为新瓶颈分了等于没分。典型错误政务系统按创建时间分片当月库压力爆表历史库空闲按单位编码分片大单位数据量是小单位的几十倍。解决方案分片键首选「高频查询维度 分布均匀」的字段如用户 ID、统一社会信用代码哈希分片时间分片仅适合冷数据归档不适合核心业务表预估数据分布偏差超过 3:1 时采用一致性哈希 虚拟节点方案坑 3分片数量拍脑袋定扩容困难现象一开始分 4 个库半年就不够用扩容需要全量数据重分布停机十几个小时。根因用简单取模分片分片数变更后所有数据的路由规则全部改变。解决方案初始分片数按未来 3 年数据量规划一次到位尽量不扩容必须支持扩容的场景采用 2 的 N 次方分片或使用一致性哈希算法政务系统优先用「按行政区域分片」扩容只新增区域不影响存量数据坑 4中间件选型跟风不考虑国产化适配现象照搬 MySQL 技术栈选了某开源分片中间件结果对金仓 / 达梦兼容极差SQL 解析全错事务频繁失败。根因多数开源分片中间件原生只支持 MySQL、PostgreSQL、Oracle对国产数据库适配不完善很多功能是 “看起来能用实际全是坑”。解决方案优先验证 ShardingSphere它对国产数据库适配相对完善金仓可指定kingbase8方言达梦可用 Oracle 方言兼容核心系统优先选择国产原厂配套的分片方案降低适配风险选型前必须做 POE 验证覆盖所有核心 SQL 与事务场景 二、SQL 兼容与语法类坑最高发占比 60%国产数据库兼容模式 分片中间件 SQL 解析相当于两层语法过滤是问题最多的重灾区。坑 5方言不配置SQL 解析全失效现象简单查询都报错分页、关联查询完全不能用日志全是 SQL 解析异常。根因ShardingSphere 通过 JDBC URL 前缀识别数据库类型金仓jdbc:kingbase8:、达梦jdbc:dm:无法被默认识别直接回退到 SQL92 标准方言大量语法解析失败。解决方案人大金仓手动指定数据库类型props: database-type: kingbase8 limit-format: LIMIT %d OFFSET %d达梦配置为 Oracle 兼容模式驱动类使用dm.jdbc.driver.DmDriver复杂场景自定义方言扩展适配国产数据库特有语法坑 6分页查询数据重复 / 丢失现象列表翻页时有的数据重复出现有的数据直接消失总数也对不上。根因分片中间件的 limit 分页逻辑与国产数据库分页语法叠加双重分页导致数据截断金仓 Oracle 兼容模式下rownum分页与 ShardingSphere 分页逻辑冲突排序字段不唯一多库归并时排序不稳定解决方案统一使用 MyBatis-Plus 分页插件由 ShardingSphere 统一处理分页业务层不手写 rownum排序字段必须包含唯一主键保证归并排序稳定性金仓关闭 Oracle 模式的 rownum 分页统一使用 LIMIT/OFFSET 语法坑 7ORDER BY 排序结果与单库不一致现象同一条 SQL单库执行和分片执行排序结果不一样NULL 值位置、大小写排序都有差异。根因各分片独立排序后中间件再做内存归并不同数据库的排序规则如 NULLS FIRST/LAST、大小写敏感与中间件归并规则不一致。解决方案显式指定 NULL 值排序规则ORDER BY name ASC NULLS LAST达梦关闭大小写敏感或排序字段统一使用大小写转换函数避免复杂的多字段混合排序尽量用数值型字段排序坑 8聚合查询结果错误现象COUNT(*)、SUM()、GROUP BY查询结果和单库统计对不上尤其是去重统计、多字段分组。根因分片中间件无法正确下推聚合函数多库结果合并逻辑错误DISTINCT、GROUP BY跨分片去重不彻底国产数据库特有聚合函数中间件不识别直接透传导致报错解决方案核心统计 SQL 提前做下推验证复杂统计建议走数仓或离线报表全局去重统计避免直接用COUNT(DISTINCT)改用应用层聚合禁止使用数据库特有聚合函数全部改用标准 SQL坑 9跨库 Join 笛卡尔积灾难现象两张分片表关联查询性能暴跌几十倍数据库 CPU 直接打满。根因两张表分片键不一致无法在单库完成关联中间件只能把两张表全量数据拉到内存做笛卡尔积关联数据量大时直接 OOM。解决方案强关联表使用相同分片键保证同分片数据在一个库实现 “绑定表” 关联小表 大表场景小表做广播表全量同步到所有分片禁止跨库多表复杂关联业务层拆分为单表查询后在内存组装坑 10使用数据库特有函数路由失败现象业务 SQL 里用了金仓SYS_*函数、达梦DM_*内置函数分片后要么报错要么全库路由性能极差。根因分片中间件无法识别国产数据库特有函数无法判断是否包含分片键只能全库执行。解决方案业务 SQL 全部使用标准 SQL 函数禁止直接调用数据库特有函数必须使用的场景通过自定义函数下推规则配置让中间件正确识别路由复杂逻辑下沉到应用层处理减少数据库依赖坑 11DDL 变更不同步现象加字段、加索引只改了部分分库业务跑起来随机报错排查半天发现是漏改了某个分表。根因人工逐个分库执行 DDL数量多了极易遗漏也没有校验机制。解决方案使用 ShardingSphere 的分布式 DDL 能力自动同步所有分片自研 DDL 执行工具批量执行并校验所有分库表结构一致性变更前做表结构对比所有分库结构完全一致再上线 三、主键与分片键类坑主键全局唯一是分库分表的基础很多项目在这里栽了大跟头。坑 12原生自增 / 序列导致主键冲突现象上线后陆续出现主键重复报错数据插入失败。根因每个分库的自增主键、序列都是独立计数的默认从 1 开始必然产生重复 ID。达梦序列默认开启缓存事务回滚时序列值不回退进一步加剧乱序风险。解决方案全局统一使用雪花算法Snowflake生成分布式 ID完全不依赖数据库自增必须用数据库序列的场景每个分库设置不同起始值 步长如 4 个库步长为 4起始值分别 1/2/3/4金仓可使用 ShardingSphere 内置的KINGBASE8_SEQUENCE主键生成器统一管理序列坑 13雪花算法时钟回拨ID 重复现象服务器时间同步异常时钟回拨导致生成重复主键数据插入失败。根因雪花算法强依赖机器时钟NTP 时间同步可能导致时间回退。解决方案引入时钟回拨检测回拨时间短则等待超过阈值则报错或切换备用工作节点使用号段模式Leaf生成 ID数据库号段分配完全不依赖时钟所有数据库与应用服务器统一 NTP 时钟源关闭自动时间同步坑 14分片键允许更新数据找不到现象修改了分片键字段值后这条数据查不出来了更新也失败。根因分片键变更后数据所在的分片变了但物理记录还在原分库路由规则找不到对应位置。解决方案分片键禁止更新业务设计时就明确为不可变字段必须更新的场景采用「删除旧记录 插入新记录」的方式保证数据路由到正确分片关键操作增加数据校验避免数据静默丢失坑 15全局唯一约束失效现象用户名、手机号等需要全局唯一的字段出现重复数据。根因分库分表后数据库唯一索引只能保证单库唯一无法跨分片校验唯一性。解决方案全局唯一字段单独建一张广播表存储唯一值做校验引入分布式锁插入前先做唯一性校验对一致性要求极高的字段考虑不分片或单独设计路由规则⚖️ 四、事务与数据一致性类坑分库分表后单机事务 ACID 被打破一致性问题是最容易引发资损和业务故障的重灾区。坑 16Transactional 失效以为还是单库事务现象跨库操作报错了前面库的数据没回滚出现脏数据。根因Spring 的Transactional只管理单数据源事务跨分片后就是多个独立事务异常时不会自动全部回滚。解决方案尽量避免跨库事务通过分片键设计让同一业务操作落在同一个分片必须跨库的场景根据一致性要求选择方案强一致XA 事务性能差国产数据库需验证驱动兼容性最终一致Seata AT/TCC、事务消息 补偿机制坑 17XA 事务各种异常回滚失败现象用了 ShardingSphere 的 XA 事务经常出现悬挂事务、提交失败、回滚不彻底数据不一致。根因国产数据库的 XA 驱动实现与开源中间件的默认适配存在差异金仓 / 达梦的 XA 协议细节和 PostgreSQL/Oracle 不完全一致。解决方案核心系统谨慎使用 XA优先通过业务设计避免跨库事务使用前必须做完整的异常场景测试宕机、网络中断、超时回滚等配合数据库厂商优化驱动版本修复已知 XA 兼容性问题坑 18Seata AT 模式建表失败回滚日志不生效现象Seata 的 undo_log 表在国产库上建表失败语法不兼容事务回滚时直接报错。根因Seata 默认的建表 SQL 是 MySQL 语法金仓 / 达梦需要适配字段类型、自增语法等。解决方案根据国产数据库语法手动改写 undo_log 建表语句适配数据类型与主键策略验证回滚逻辑正常提交、异常回滚、超时重试等场景全覆盖达梦建议用 Oracle 模式兼容金仓用 PG 模式兼容坑 19读写分离 分库分表叠加读到脏数据现象刚写入的数据马上查不到过几秒又出现了业务逻辑错乱。根因分库分表同时配置读写分离写入主库后主从同步有延迟查询路由到备库就读不到最新数据。解决方案强一致性读强制走主库通过 Hint 动态指定路由配置主从延迟阈值延迟过大时自动切回主库查询金仓 / 达梦主备集群配置同步模式保证提交时备库已回放 五、运维与扩容类坑分库分表后运维复杂度指数级上升很多团队前期完全没考虑运维成本。坑 20扩容数据重分布数据丢失 / 重复现象新增分片后数据迁移过程中出现丢数据、重复数据业务校验不通过。根因自研迁移脚本有 bug边界处理不当迁移过程中业务还在写入数据变化没同步国产数据库特有数据类型迁移时转换错误解决方案迁移前全量备份所有分片数据采用「双写 迁移 校验」方案先开启双写再迁移历史数据最后全量校验一致后切换路由迁移工具提前做数据类型兼容性验证坑 21备份恢复困难时间点对不上现象出问题需要回滚时十几个分库备份时间点不一致恢复后数据错乱。根因每个分库独立备份无法保证全局一致性时间点恢复后跨库数据不一致。解决方案备份前先停写或做全局一致性快照所有分库统一备份时间点同步执行备份关键系统搭建延迟从库需要回滚时先切到延迟从库恢复坑 22监控缺失排障全靠猜现象系统慢了不知道哪个库慢报错了不知道路由到哪个分片排查问题像盲人摸象。根因只监控了整体数据库指标没有分片维度的监控也没有 SQL 路由链路追踪。解决方案监控覆盖每个分片的 CPU、连接数、慢 SQL、表空间使用率接入链路追踪打印每条 SQL 的实际路由节点、执行时间慢 SQL 必须能定位到具体分库分表针对性优化 六、国产数据库专属坑最容易忽略这些坑是国产数据库特有场景照搬 MySQL 经验一定会翻车。坑 23大小写敏感导致路由错误现象分片键值大小写不一致时路由到错误的分库数据查不到。根因达梦默认开启大小写敏感金仓可配置分片中间件按字符串哈希计算路由时大小写不同会得到完全不同的哈希值。解决方案初始化实例时统一关闭大小写敏感CASE_SENSITIVE0政务项目推荐配置分片键入库前统一转大写或小写保证路由计算一致性分片算法中增加大小写归一化逻辑坑 24国密透明加密 分片扩容迁移失败现象每个分库的透明加密密钥独立数据迁移到新分片后无法解密数据乱码。根因国产数据库透明加密按实例生成密钥不同分片实例密钥不同加密数据无法跨实例迁移。解决方案所有分片统一使用外部密钥管理系统KMS密钥全局一致敏感字段加密在应用层做不使用数据库透明加密扩容迁移时先解密、再迁移、再加密全程校验数据完整性七、分库分表避坑黄金准则7.1 设计三原则能不分就不分优先分区表、读写分离分库分表是最后选项分片键优先所有设计围绕分片键展开尽量让核心操作都落在单分片复杂度可控分片数量不宜过多单库单表数量控制在合理范围7.2 SQL 编写规范所有查询尽量带上分片键避免全库路由禁止跨库复杂 Join、子查询、存储过程使用标准 SQL不依赖数据库特有语法核心 SQL 必须做分片路由验证确认执行计划符合预期7.3 运维红线所有 DDL 必须批量执行全分片结构一致性校验通过才能上线扩容必须有完整回滚方案先演练再生产执行监控必须覆盖到单分片维度故障可快速定位八、全文总结分库分表从来不是性能银弹而是用复杂度换扩展性的技术方案。在国产数据库生态尚不完善的阶段盲目照搬 MySQL 生态的玩法必然会踩进各种兼容性大坑。比 “怎么分” 更重要的是 “要不要分”。前期做好评估选对分片键中间严控 SQL 质量后期完善运维体系才能真正发挥分库分表的价值同时把风险控制在可接受范围内。希望这 24 个踩坑总结能帮你在信创改造路上少走弯路。