SQL Server存储过程多人协作必须依赖Git等版本控制,禁止直接在数据库中修改;CREATE OR ALTER仅保障部署原子性,不解决开发冲突;合并需人工审查逻辑语义(如WHERE、JOIN),而非仅依赖Git行级比对。

存储过程被多人同时修改,SQL Server里怎么避免覆盖
直接说结论:SQL Server本身不提供类似Git的分支合并能力,CREATE OR ALTER PROCEDURE不是万能解药,它只管“最终生效”,不管“谁改了哪一行”。冲突发生在开发阶段,不是执行阶段。
常见错误现象是:A在本地改了usp_GetUserOrders的WHERE条件,B在另一台机器上加了@IncludeArchived参数,两人先后执行CREATE OR ALTER,后执行的人会彻底抹掉前一个人的改动——没有提示,没有报错,只有逻辑静默丢失。
- 所有存储过程必须纳入版本控制(.sql文件),不能只靠SSMS“生成脚本”临时保存
- 每次修改前先
git pull,确认usp_GetUserOrders.sql本地和远程一致 - 禁止直接在生产/测试库上右键“修改”再执行——这种操作绕过版本控制,等于开盲盒
- 如果必须现场调试,用
SELECT OBJECT_DEFINITION(OBJECT_ID('usp_GetUserOrders'))把当前定义捞出来,另存为临时文件比对
用Git合并.sql文件时,如何识别真正的逻辑冲突
SQL存储过程文本看起来像代码,但Git的行级合并常失效:一个空格、注释位置、换行风格(CRLF vs LF)都可能触发假冲突;而真正危险的逻辑变更(比如两人都改了同一个JOIN条件)反而因格式一致被Git“安静”合并过去。
关键判断点不是“有没有标红”,而是“语义是否互斥”。例如:
-- A的提交:ON u.id = o.user_id AND o.status != 'cancelled' -- B的提交:ON u.id = o.user_id AND o.created_date > DATEADD(day, -30, GETDATE())
Git可能把这两行合成一句,但结果是AND连用,逻辑已变——这不是语法错误,是业务逻辑覆盖。
- 合并后必须人工检查所有
WHERE、JOIN、ORDER BY和INSERT ... SELECT子句是否被意外叠加或删减 - 用
sqlfluff或tsqlt做基础格式校验,但别依赖它发现逻辑冲突 - 把存储过程拆成“接口层+逻辑层”,比如
usp_GetUserOrders只做参数校验和调用usp_GetUserOrders_Core,后者单独文件,专注逻辑——缩小人工审查范围
SQL Server 2016+ 的CREATE OR ALTER到底该不该用
该用,但仅限于部署环节。它解决的是“不存在就建、存在就改”的原子性问题,不是协作冲突问题。
容易踩的坑是:把它当成“安全覆盖”指令,误以为只要用了CREATE OR ALTER,本地改完就能直接上线。实际中,如果本地文件没同步最新版,CREATE OR ALTER只是把旧逻辑重新刷上去,线上就回退了。
-
CREATE OR ALTER不会校验依赖关系——比如你删了usp_GetUserOrders里引用的fn_CalculateFee,它照样执行成功,等运行时报The scalar function "fn_CalculateFee" does not exist - 在CI流程里,必须在
CREATE OR ALTER前加一步:sqlcmd -S server -d db -i check_dependencies.sql,查sys.dm_exec_describe_first_result_set确保所有引用对象存在 - 对带加密的存储过程(
WITH ENCRYPTION),CREATE OR ALTER会清空原有加密内容,明文暴露——这种过程必须手动导出再导入
为什么不用Redgate SQL Compare或ApexSQL Diff自动合并
这类工具能比对两个数据库的存储过程差异,生成同步脚本,但它们解决的是“环境间同步”,不是“开发中协同”。当你在dev库改了一版,在test库又手改了一版,工具能告诉你“test比dev多一行UPDATE”,但它没法告诉你“这行UPDATE是不是应该保留”。
更麻烦的是:它们默认按对象名匹配,如果A把usp_GetUserOrders重命名为usp_GetActiveUserOrders,B在同一时间新增了同名过程,工具可能判定为“删除+新建”,而不是“重命名+修改”,导致上线脚本误删关键过程。
- 只在发布前用——比对staging和prod,确认部署包没漏东西
- 绝不用于开发机之间同步:本地改的还没进Git,用工具推到同事库,等于跳过Code Review
- 配置时禁用
Ignore whitespace以外的所有“忽略”选项,否则AND o.status = 'active'和AND o.status = 'active'会被判为无差异
最麻烦的点其实是人:两个开发者都觉得“我这个修改更紧急”,都不愿先拉取再改,最后靠加班手动逐行比对sys.procedures的modify_date和Git日志来倒查。这事没法自动化,只能靠流程卡点。

















