shardingsphere、mycat等分库分表中间件不支持call语句的分片路由,因其仅解析标准dml,无法识别存储过程内部分片键、动态sql及跨库事务逻辑,导致广播执行、报错或数据不一致。

CALL语句无法被分片中间件路由
分库分表后,CALL 语句在 ShardingSphere、MyCat 或自研中间件中基本不被解析。中间件只识别 SELECT/INSERT/UPDATE/DELETE 等标准 DML,而 CALL 被当作“未知命令”处理——结果通常是广播到所有分片,或直接报错 ERROR 1312 (0A000): PROCEDURE can't be executed in a transaction。
即使强行配置路由规则,也无法解决跨库逻辑:比如一个存储过程里先查 order_001,再更新 inventory_003,中间件无法保证这两个操作落在同一物理连接上,更无法协调分布式事务。
- ShardingSphere-Proxy 5.3+ 对
CALL仅支持透传(passthrough),不参与分片计算 - MyCat 2.x 默认拒绝
CALL,需手动开启enableProcedure=true,但依然不支持参数化分片键路由 - 阿里云 DTS 或 cdc 工具同步时,
CALL不会触发 binlog 记录,导致下游数据丢失
存储过程内部 SQL 无法命中分片键
分片中间件依赖 SQL 中显式的分片字段(如 WHERE user_id = ?)做路由判断。而存储过程内嵌的动态拼接 SQL、游标循环、临时表操作,会让分片字段隐藏在变量或逻辑分支中,中间件根本无法提取。
例如这段代码:
DECLARE v_uid BIGINT DEFAULT 0; SELECT id INTO v_uid FROM users WHERE name = p_name LIMIT 1; UPDATE orders SET status = 'paid' WHERE uid = v_uid;
中间件看到的只是 CALL proc_pay('alice'),后续的 SELECT 和 UPDATE 完全不可见,自然无法把 UPDATE 路由到 orders_002。
- 使用
CURSOR遍历结果集时,每次FETCH都可能跨不同分片,但中间件无感知 -
PREPARE/EXECUTE动态 SQL 的表名和条件全是运行时决定,分片策略彻底失效 - 哪怕加了注释提示
/* sharding: table=orders, shardingKey=uid */,中间件也不解析存储过程体内的注释
主从延迟 + 读写分离下行为不可控
存储过程中混用读写语句(如先 SELECT 再 UPDATE),在读写分离架构下极易出问题。从库只回放 binlog,但不会执行存储过程体——除非你用 SBR(Statement-Based Replication),而 SBR 在分库分表场景本身就被弃用。
更麻烦的是:SBR 要求主从 sql_mode、time_zone、rand_seed 完全一致,否则 NOW()、RAND() 类函数在从库执行结果不同,直接导致数据不一致。
- RBR(Row-Based Replication)下,存储过程调用会被记录为
CALL ...语句事件,从库重放时仍需执行完整过程,但此时从库可能没权限或没定义该过程 - 如果过程里用了
SELECT ... FOR UPDATE,主库锁行成功,但从库重放时因无锁机制,可能跳过等待直接报错 - 应用层读取刚写入的数据,若走从库,大概率读不到最新状态(尤其涉及状态流转的业务)
调试与监控完全失焦
当 CALL settle_account() 执行慢,你没法知道是哪一行 SQL 卡住:performance_schema 只记一条 CALL 记录;slow_query_log 不记录过程内子查询;general_log 满屏 BEGIN/END 噪声,关键逻辑被淹没。
死锁日志里只显示线程 ID,不带过程名;Prometheus 抓不到 OUT 参数值;binlog event 里没有实际影响行数统计——等于把可观测性主动关掉。
- MySQL Workbench 调试器无法 attach 到线上已运行会话,只能本地单步,脱离真实负载环境
- 无法对存储过程做单元测试:没有类似 JUnit 的框架支持 mock 表、注入异常、验证中间状态
- 一旦过程里调用
SLEEP(1)或隐式锁表,整个数据库连接会被占住,innodb_thread_concurrency资源迅速耗尽
分库分表不是“加个中间件就完事”,它把原本单库的确定性,换成多节点的协作不确定性。存储过程却反其道而行之,把本该暴露给应用层调度的逻辑,锁死在单个数据库实例里——这种根本性的矛盾,不是调参或升级版本能绕开的。











