LOGO 首页 OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 技术文档 其他文档  
 
网站管理员

分库分表,可能真的要退出历史舞台了

admin
2026年10月17日 15:53 本文热度 200

我的手上有一个 2019 年的订单项目,库分了 16 个,路由代码中那句 user_id % 16 到现在还在运行

前几天按照这套查询逻辑在 TiDB 上重新构建了一番,代码中那个“%”一个都没有了

因此本文不谈趋势,只讲分片这件事是如何从应用层面迁移到数据库内核之中的,每一个步骤都伴随着 SQL 以及配置

先算清楚分库分表到底哪里贵

很多人以为贵的就是"拆表"那一瞬间,其实贵的是拆完之后,在应用层自己维护一个分布式系统

分片键要出现在所有的查询条件中,少了任何一个就会变成全分片扇出

深度分页最典型的例子就是 LIMIT 1000000, 10,它会把 16 个分片分别捞出 100 万行的数据来合并,而数据库实际上干了 1600 万行的活

扩容方案在第一天就因为分片算法而被锁定。取模分 16 个库想扩到 32 个,就是全量数据重分布,一致性哈希可以少迁点,但是也必须迁

跨分片事务、全局唯一 ID、跨库 JOIN,在单机上数据库免费送给你,拆开来全部要自己造一遍

最省事的一刀:原生分区表

如果只是单表太大、还用不上分布式数据库的话,那么 MySQL 自带的分区表就能撑一段时间

它的原理就是逻辑上一张表、物理上多个 ibd 文件,SQL 语法一个字不用改,路由由内核按分区表达式计算

 -- 按 user_id 哈希分 16 个物理分区,应用层 SQL 完全不用动
CREATE TABLE t_order (
  order_id BIGINTNOT NULL,
  user_id  BIGINTNOT NULL,
  amount   DECIMAL(10,2),
PRIMARY KEY (order_id, user_id)   -- 分区列必须落在每个唯一键里,原因见下
) PARTITIONBY HASH(user_id) PARTITIONS 16;

有一个很容易出问题的硬性规定:分区表达式所用到的列,在这张表的所有唯一索引中都必须出现,主键也包括

你要是把主键只写成 PRIMARY KEY (order_id),再按 user_id 分区,MySQL 直接甩你一个 ERROR 1503

其实道理并不复杂,在物理层面上已经把不同分区隔离开来了,所以跨分区就无法进行唯一性校验了,因此它干脆就不让你创建这样的表

代价也要交代清楚,order_id 单独不唯一了,全局唯一订单号需要依靠发号器或者雪花算法来保证,这个账迁移之前就要算清楚

裁剪的验证方法很简单,在 EXPLAIN 输出中有一个 partitions 列,如果命中的是单个分区,则说明该裁剪生效;没有分区键的查询会扫描所有 16 个分区,这就和没有分区一样

再加上 ALTER TABLE ... EXCHANGE PARTITION、DROP PARTITION 等命令,历史数据归档的速度可以达到秒级,不需要再写批量 DELETE 熬夜加班

但是它的天花板也十分明显,机器依旧是那一台,IO 和连接数该顶还是顶,这就是分区表和分布式数据库之间的分水岭

把分片真正下沉到内核

TiDB 的答案就是 Region。按照 key range 的方式把数据切成了默认的 96MB 一个 Region,写满之后会自动分裂,PD 负责把 Region 调度到不同的 TiKV 节点上。同时把全局递增的 TSO 分发出去

应用只需要连一个 MySQL 协议地址,跨 Region 的事务走 Percolator 两阶段提交,这些都是对业务代码完全隐形的

但是有一个坑,这个坑很具体

 -- 自增主键生成的 ID 单调递增,会连续落在同一个 Region 上,热点就是这么来的
id BIGINTPRIMARY KEY AUTO_INCREMENT

-- 换成 AUTO_RANDOM,把高位打散,写入才能真正铺到整个集群
id BIGINTPRIMARY KEY AUTO_RANDOM(5)

这是从 MySQL 迁移过来最常出现的翻车点,表建好、数据也导入进去之后,压测一跑就发现只有一个 TiKV 在扛

OceanBase 的路子更加接近传统的 DBA 直觉,原生分区表加上分区键由用户自己来指定,副本之间通过 Paxos 同步,RPO 等于 0,RTO 压在 8 秒以内

PolarDB MySQL 的多主集群(Limitless)是另外一种思路,它做的就是库表级别的写入点下移

 -- 把库挂到指定写入节点,而不是让你在代码里算哈希
CREATE DATABASE db1 POLARDB_WRITE_NODE 1;
-- 会话要切到目标节点才能干活
ALTER SESSION POLARDB_WRITE_NODE 2;

文档写得很实在:跨 RW 节点的查询不支持,跨节点的 DDL 直接报错

其实它并没有消灭分片,而是把分片藏到了数据库里面,代价就是换了一个地方支付

真要迁移的话,落地路径会是这样的

迁移的时候最忌讳的就是拍脑袋了,TiDB 那套 DM 工具已经把分库分表合并做成了配置

 # 把 shard_0..shard_15 里的 t_order 合并成下游一张表
name:merge-order
task-mode:all
shard-mode:pessimistic
routes:
merge-order:
schema-pattern:"shard_*"
table-pattern:"t_order"
target-schema:"biz
    target-table: "
t_order"

全部拉取完毕之后,DM 会自动切换到 binlog 增量同步模式,在这个切换的过程中,业务不需要停止

决定成败的是校验这一环节,这一步不要偷懒

行数对一遍只能算第一层,往上还有表级 checksum,最后用 sync-diff-inspector 做全字段逐行比对,在配置中将 export-fix-sql 打开来,不一致的行它会直接生成修复 SQL

有一个限制我必须提前说清楚:从 MySQL 到 TiDB 之间不支持在线校验,在校验范围内数据要保证不再变动,因此灰度窗口要提前划定好,不能边写边校

我的判断

分两种情况说

单表大但是还在单机范围内的话,就老老实实上分区表吧,先把 ERROR 1503 那个唯一键约束想清楚了,能省下一整层中间件

分片键已经不能再修改了,跨库 JOIN 把接口拖到了几百毫秒,扩容要停服做数据迁移的,那么就不要硬撑下去了,这笔钱花的是把复杂度从开发身上挪走

至于“退出历史舞台”的说法,我认为应该这样修:退出的是应用层手写哈希、手动拼跨库查询这个阶段,分片本身不会消失,它只是从你的 % 16,变成内核里的 Region 和分区表


阅读原文:点击这里​


该文章在 2026/10/17 15:53:54 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-9  粤公网安备44030602007207号