vtgate未走预期分片主因是sql含非vindex列的where条件或跨分片join,导致scatter/gather;仅where分片键=常量可单分片路由,in需全常量且数量≤max_in_count,vindex类型与配置错误亦会失效。

VTGate 的 query routing 为什么没走预期分片?
VTGate 默认按 Vindex 值路由,但只要 SQL 里出现非 Vindex 列的 WHERE 条件(比如 WHERE status = 'active'),它就无法确定目标分片,会退化为 scatter/gather。
- 确认是否用了
Vindex对应列:比如分片键是user_id,那只有WHERE user_id = 123才能单分片路由 - 避免在
WHERE中混用非分片字段——哪怕加了索引也没用,VTGate 不查底层表结构 -
EXPLAIN输出里看到Route: Scatter或多个Keyspace: xxx, Shard: -80,80-就是典型信号 - 联合查询(
JOIN)跨分片时,VTGate 一律 scatter/gather,不尝试重写或下推
scatter/gather 查询慢,怎么定位瓶颈?
慢不一定是网络或分片多,更可能是 VTGate 自身串行执行、结果合并开销大,或者下游 mysql 连接池打满。
- 检查
vtgate日志里的QueryDuration和ScatterDuration字段:前者长说明单分片慢,后者长说明并发调度/聚合耗时高 - 用
SHOW viteSS_STATUS看ActiveScatterQueries是否持续高位,结合MaxOpenConnections配置判断连接池是否成为瓶颈 - 避免在 scatter/gather 查询中 select 大字段(如
TEXT、BLOB),VTGate 要在内存里拼整行再返回,OOM 风险陡增 - 如果只是 COUNT 或 SUM,优先改用
SELECT SUM(col) FROM t GROUP BY 1形式,让 VTGate 能做部分聚合,减少回传数据量
想强制单分片路由,但 IN 或 OR 让 VTGate 放弃优化
VTGate 对 IN 的处理很保守:只要列表长度 > 1,且不是完全由常量构成(比如含子查询、变量、函数),就会 fallback 到 scatter。
- 安全写法只有一种:
WHERE user_id IN (1001, 1002, 1003)—— 全常量、无表达式、数量别超 50(默认max_in_count限制) -
WHERE user_id = ? OR user_id = ?等价于IN,同样受限制;用union ALL拆成多个单值查询反而更稳 - 修改
vtgate启动参数--max_in_count=200可放宽限制,但注意内存占用会上升,尤其配合SELECT * - 不要依赖
HINT强制路由:Vitess 目前不支持类似 MySQL 的/*+ USE_INDEX */语法控制分片选择
用 vtctlclient 查路由策略,但输出看不懂
vtctlclient GetRoutingRules 和 GetVSchema 返回的是原始 json,关键信息藏得深,容易误读分片逻辑。
- 重点盯
vindexes下的type字段:unicode_loose_md5是哈希分片,lookup是映射表,binary是范围分片——类型不同,路由行为差异极大 -
tables里每个表的column_vindex必须和vindexes名称严格匹配,大小写敏感,配错就等于没分片键 - 执行
vtctlclient ValidateVSchema能发现大部分配置矛盾,比如分片键字段不存在、Vindex 类型不支持该字段类型等 - 别信
vtctlclient GetSrvKeyspace的Shards列表——它只显示拓扑,不反映当前查询是否真能落到这些 shard 上
分片键设计一旦上线就很难改,Vindex 类型选错、字段类型不匹配、或早期没预留足够 shard 数量,都会让后续所有 query routing 优化失效。这些不是配置问题,是架构决策点,调参绕不过去。