是的。tidb默认建表仅生成1个region,导致写入集中于单tikv节点形成热点;预切分是批量导入、日志表初始化等场景的必要前置动作,否则pd无法调度。

新建大表写入前必须预切分 Region 吗?
绝大多数情况下,是的。TiDB 默认建表只生成 1 个 Region,所有写入都落在同一 TiKV 节点上,哪怕集群有 20 台 TiKV,初期写入也必然形成单点热点——这不是调度慢的问题,而是数据编码规则决定的:tablePrefix{tableID}_recordPrefixSep{rowID} 这一 Key 结构导致新行按 rowID 递增追加,而默认整型主键或隐式自增 rowID 都是顺序值。
预切分不是“可选优化”,而是应对批量导入、日志表初始化、订单号时间序主键等场景的必要前置动作。不预切分,PD 的 balance-region 和 balance-leader 调度器根本无 Region 可调度。
- 适用场景:批量导入 > 100 万行、日志类宽表建完即写、主键为
BIGINT自增或UNIX_TIMESTAMP类时间戳 - 不适用场景:小配置表(
- 错误现象:
tidb_server_handle_query_duration_seconds_bucket99 分位突增、某 TiKV 实例store_write_flow_bytes持续高于其他节点 3 倍以上
用 BETWEEN 还是 BY 手动指定 Split 点?
看你的主键/分区键分布是否均匀。BETWEEN lower_value AND upper_value REGIONS region_num 是等距切分,假设你建表时用 id BIGINT PRIMARY KEY,且预计最终数据范围是 1 ~ 10 亿,想预切 64 个 Region,就写 BETWEEN 1 AND 1000000000 REGIONS 64——PD 会自动算出每段边界,但前提是数据真按这范围线性分布。
而 BY value_list... 更适合非均匀场景:比如按业务线拆分的订单表,华东 ID 段集中于 1~5000 万,华南集中在 5001 万~5050 万,其余稀疏,这时硬用 BETWEEN 会导致某些 Region 空载、某些仍热点。
-
BETWEEN:简单、适合整型主键 + 数据量可预估,但若实际写入远少于预期,会造成 Region 过碎,增加region-meta内存开销 -
BY:需人工分析数据分布(例如查HISTOGRAM或抽样COUNT GROUP BY FLOOR(id/1000000)),切分点必须严格升序,且不能包含重复值 - 参数差异:
REGIONS N是目标总数;BY (v1,v2,...)切出的是N+1个 Region(N 个切点 → N+1 段)
split-region-size 调大能缓解热点吗?
不能,反而可能加剧。默认 split-region-size = 64MB 是触发自动分裂的阈值,它只影响“已有 Region 何时分裂”,不解决“初始只有一个 Region”的根本问题。调到 128MB 后,那个初始 Region 得写满 128MB 才分裂——意味着更长时间内所有写请求还在打同一个 TiKV。
真正该调的是预切分行为本身,以及配合 PD 的调度节奏。如果你观察到预切分后 Region 打散缓慢(tidb_wait_split_region_finish = 0 时返回快但实际没完成),说明 PD 正在排队调度,此时强行调大 split-region-size 只会让每个 Region 更“胖”,加重单点负载。
- 正确做法:建表语句末尾加
SHARD_ROW_ID_BITS = 4(对非自增主键表)或显式SPLIT REGION,再确认pd-ctl中region status显示"approximate_size": 60左右(单位 MB)且分布均匀 - 错误操作:在热点已发时才去改
split-region-size,这属于“治标不治本”,且需滚动重启 TiKV 才生效 - 性能影响:调得过大(如 512MB)会导致单 Region Raft 日志体积膨胀,影响 snapshot 传输和恢复速度
怎么确认预切分真的生效了?
别信 sql 返回成功,要看 Region 实际分布。最直接的方式是用 pd-ctl 查表对应 Region 是否已分散到多个 Store:
pd-ctl region key "t_22_r"
其中 t_22_r 是表 ID 22 的 record 前缀(可通过 SELECT TIDB_TABLE_ID FROM information_schema.tables WHERE table_name='your_table' 查)。如果返回多个 Region,且每个的 leader.store_id 不同,才算打散成功。若多数 Region leader 都挤在 store_id=1 上,说明 PD 还没调度完,或该 Store 负载过高被调度器跳过。
- 关键指标:执行
pd-ctl store看各 store 的leader_count和region_count是否接近均值(偏差 - 容易忽略的坑:
tidb_wait_split_region_finish默认为 1,但若设为 0,SQL 会立即返回,你以为切完了,其实只是把 Operator 提交给了 PD 队列,后续还需等operator_status变为finished - 验证时机:建议在批量写入开始前 2 分钟检查,避免边写边切导致部分 Region 仍空载
预切分不是“设完就完”的开关,Region 打散完成与否取决于 PD 当前调度队列长度、目标 TiKV 的负载水位、以及是否存在 Label 约束冲突——这些都不会在 SQL 返回里告诉你。