存储过程面试核心是逻辑正确性与性能优化能力。需掌握执行计划分析、参数嗅探应对(如局部变量赋值、option(recompile))、事务粒度控制、参数化查询防注入、动态sql安全处理(quotename+sp_executesql)、分批更新及索引优化策略。

存储过程面试常考两点:能不能写对逻辑,会不会优化性能。很多候选人能写出基础增删改查,但一遇到高并发、大数据量或复杂业务就卡壳。关键不在语法多难,而在是否理解执行计划、参数嗅探、事务边界这些底层机制。
参数化查询与避免动态SQL拼接
面试官常问“如何防止SQL注入又保持灵活性”。硬拼字符串是典型错误答案。正确做法是用参数占位符,哪怕在存储过程中也要坚持。
- 用 @param 接收输入,所有 WHERE、JOIN 条件都绑定参数,不拼字符串
- 真需要动态列或表名(如分表查询),用 QUOTENAME() 包裹对象名,再配合 sp_executesql 执行
- 别用 EXEC('...') —— 它绕过执行计划缓存,每次编译,还无法参数化
减少锁争用与事务粒度控制
存储过程里一个 BEGIN TRAN 包到结尾,是线上事故高频原因。事务越长,阻塞越多,死锁概率越高。
- 只把真正需要原子性的操作放进事务,比如“扣库存+写订单”必须一起成功或失败
- SELECT 不要加 WITH(NOLOCK) 当默认方案——它解决不了根本问题,反而带来脏读风险;优先考虑索引覆盖、减少扫描范围
- 大更新分批做:用 TOP + WHERE ID > @lastId 循环处理,每次事务控制在几百行内
利用执行计划定位瓶颈
面试时被问“慢怎么查”,光说“加索引”不够。得讲清楚怎么看实际执行计划里的关键信号。
- 关注红色警告图标:缺少索引、隐式转换、表扫描(Table Scan)、聚集索引扫描(Clustered Index Scan)
- 看“实际行数 vs 预估行数”偏差大?大概率是统计信息过期,运行 UPDATE STATISTICS 或加 WITH RECOMPILE 强制重编译
- 嵌套循环(Nested Loops)在小数据量快,但外层输出行多时会爆炸——这时该换哈希匹配(Hash Match)或合并连接(Merge Join)
避免参数嗅探陷阱
同一个存储过程,第一次用 @status = 'A' 编译的计划,后续 @status = 'Z'(数据极少)也复用,结果走全表扫描,性能骤降。
- 局部变量赋值法:把入参赋给本地变量再用,让优化器放弃嗅探
- OPTION (RECOMPILE):适合参数值分布极不均匀、且执行频率不高的场景
- 使用 OPTIMIZE FOR UNKNOWN:SQL Server 2008+ 支持,让优化器按平均分布估算










