先说几个核心判断:把 SQL Server 的存储过程直接搬到分布式数据库?几乎不可能跑得通。语法兼容层能帮你解决 TOP、IDENTITY、PIVOT 这类表面问题,但底层的锁机制、事务模型、执行计划缓存——这些才是真正要命的坑。一旦跨分片路由,原存储过程要么报错(Msg 7395 事务未升级、xp_cmdshell 被禁用),要么看似成功但数据已经对不上了。

单机语义必须彻底剥离
分布式数据库的两阶段提交或最终一致性模型,和 SQL Server 的单机强事务有着本质差异。那些依赖会话状态的写法——比如 @@ROWCOUNT、SET TRANSACTION ISOLATION LEVEL——在分片之间根本没法全局生效。还有 SELECT INTO 隐式建表,表元数据可能跨节点不一致。更别提四部分命名([srv_link].db.schema.table),链接服务器这种概念在分布式架构里压根不存在。
- 所有依赖单机语义的逻辑必须删除,包括但不限于
@@ROWCOUNT、SET TRANSACTION等会话状态指令 - 禁止使用
SELECT INTO或任何隐式建表操作 - 硬编码四部分命名直接禁用,分布式环境下根本没有对应的链接对象
环境标识靠参数传递,拒绝运行时推断
很多老项目喜欢在存储过程里用 SERVERPROPERTY('MachineName') 或者查系统视图来判断当前是开发环境还是生产环境。这一套在容器化、多租户、蓝绿发布的环境里完全失效。MySQL 的 @@hostname、PostgreSQL 的 current_setting('app.env') 同样不可靠——环境变量可能被误改,甚至因为部署拓扑变化返回错误值。
唯一靠谱的路子:让应用层把环境标识(比如 'dev'、'prod')作为显式参数传进来,存储过程内部不做任何推断。
- SQL Server 改法:
CREATE PROCEDURE usp_process_order @p_env NVARCHAR(10),开头加上IF @p_env NOT IN ('dev','prod') ...校验 - MySQL 改法:强制声明
IN p_env VARCHAR(10),禁用SET @env = IFNULL(@env, 'dev')这种兜底写法 - PostgreSQL 改法:放弃
current_setting('app.env'),改用函数参数env TEXT DEFAULT 'dev'并显式传入
放弃分布式事务,拥抱最终一致性
SQL Server 的 BEGIN DISTRIBUTED TRANSACTION 依赖 MSDTC,分布式数据库里根本没有对应组件。强行模拟会有大的麻烦——网络分区或节点故障会导致事务悬挂,甚至静默降级,数据不一致几乎必然发生。
务实做法是接受短暂不一致,用本地消息表加异步补偿来替代两阶段提交。这算不上什么新鲜方案,但在跨分片场景下确实是最稳定的。
- 在业务库创建
outbox_message表,字段包含event_type、payload、status、created_at - 主流程在同一个本地事务里写业务数据,同时插入一条状态为
pending的消息记录 - 独立投递服务轮询这张表,把消息发到 Kafka/RocketMQ;下游消费成功后再更新
status = 'sent' - 所有跨分片写操作都走这个通道,不要再试图在存储过程里发起远程 DML
方言逻辑抽离为独立 SQL 文件,按库加载
有些项目试图在单个存储过程里用 IF @@VERSION LIKE '%PostgreSQL%' 来分支判断数据库类型——这种方式既难测试也不符合分层原则。分布式数据库往往混合部署,核心交易可能用金仓,报表用 PostgreSQL,同一套 SQL 需要适配多种后端。
正确做法是把所有非标准逻辑拆出来,按目标数据库命名,由应用配置决定加载哪一份。所有标识符(表名、列名、参数名)强制小写加下划线,禁用 @param、双引号包裹、大小写混用这类方言特性。
- 分页逻辑分别存为
limit_offset_sqlserver.sql、limit_offset_postgres.sql、limit_offset_kingbase.sql - UUID 生成统一用
gen_random_uuid()(PG)、NEWID()(SQL Server)、sys_guid()(Oracle)——但这些函数名不能出现在通用存储过程中,只能放在各自的方言文件里
跨分片事务的边界模糊性最容易被忽略:你以为操作的是“一个数据库”,实际 SQL 可能路由到多个物理节点。任何依赖会话状态(临时表、用户变量)、锁粒度(页锁 vs 行锁)、或执行顺序(触发器触发时机)的逻辑,到了分布式环境下都会失效。适配不是语法转换,而是对数据一致性和操作原子性的重新定义。
