怎么让SQL Server的语句跑得更快,优化那些容易忽略的小细节
- 问答
- 2026-01-12 04:36:22
- 2
养成查看执行计划的习惯,但别只看图形界面 很多开发者知道要查看执行计划,但往往只盯着图形界面看哪个步骤的“成本百分比”最高,来自知乎用户“老兵”的建议是,要重点关注执行计划里的“实际执行计划”而非“预估执行计划”,因为预估可能不准,更重要的是,要留意几个关键操作符:

- 表扫描(Table Scan):这通常是性能杀手,意味着数据库在扫整个表,就像在图书馆里找一本书却要翻遍每一个书架,出现这个,第一反应就是检查是否缺少索引。
- 键查找(Key Lookup)或RID查找:这通常发生在非聚集索引查找后,还需要回到主表(堆表或聚集索引)去获取其他列的数据,博客园专家“潇湘隐者”指出,频繁的键查找会造成大量随机IO,即使单次很快,次数多了也非常耗时,解决方案是考虑创建覆盖索引(Include Index),把查询中需要的列包含在索引的叶子节点中,避免回表。
- 隐式转换(Implicit Conversion):在执行计划的警告信息(如黄色感叹号)里,经常会看到这个提示,这意味着你WHERE条件里的数据类型和表结构定义的不一致(比如表里是VARCHAR字段,你却用了数字去查询),导致SQL Server不得不隐式转换整个列的数据类型再来比较,这会使得索引失效,这是最容易被忽略的细节之一。
警惕参数嗅探(Parameter Sniffing)问题
这是一个经典且隐蔽的问题,知乎专栏“SQL Server深度解析”这样解释:当存储过程或参数化查询第一次编译时,SQL Server会根据传入的参数值来生成一个“认为最优”的执行计划并缓存起来,如果第一次传入的参数很特殊(比如返回数据量极少),那么生成的执行计划可能对后续常规参数(返回数据量很大)极其不利。
第一次用“城市=’拉萨’”(数据少)编译,生成了索引查找计划;第二次用“城市=’上海’”(数据多),按理说表扫描更高效,但它却复用了之前的索引查找计划,导致性能骤降,解决方法有很多,比如使用OPTION (RECOMPILE)让语句每次重编译、使用OPTION (OPTIMIZE FOR UNKNOWN)或使用本地变量屏蔽参数值等,关键在于要意识到这个问题存在,而不是一味地责怪索引没用。

注意查询的书写方式,避免让优化器“为难”

- 不要在WHERE条件中对字段进行函数操作:比如
WHERE YEAR(CreateDate) = 2023,这样写会使CreateDate字段上的索引无法使用,应该写成范围查询:WHERE CreateDate >= '2023-01-01' AND CreateDate < '2024-01-01',这个道理很多人都懂,但在复杂的业务逻辑拼接SQL时很容易疏忽。 - 小心使用NOT IN和<>操作符:这类否定查询往往难以有效利用索引,CSDN博客专家指出,很多时候可以尝试改写为LEFT JOIN ... IS NULL的方式,或者如果数据状态不多,改用IN查询正面列举。
- *避免使用`SELECT
**:这不仅浪费网络带宽和内存,更严重的是,如果表上有非聚集索引,但你的查询需要SELECT *`获取所有列,优化器可能会认为回表成本太高,而直接选择效率更低的表扫描,只查询需要的列,能增加使用更高效的窄索引的机会。
索引的维护比创建更重要 很多团队花了大力气设计了一堆索引,然后就放任不管了,来自腾讯云+社区的文章强调,索引是需要维护的。
- 索引碎片化:数据频繁增删改,会导致索引页产生碎片,就像一本被反复撕掉和插入页的书,查找效率会越来越低,需要定期(比如每周)对重要索引进行重组(ALTER INDEX ... REORGANIZE)或重建(ALTER INDEX ... REBUILD)。
- 缺失索引和冗余索引:SQL Server本身会记录一些“缺失索引”建议,可以在DMV(动态管理视图)中查询
sys.dm_db_missing_index_details,但这些建议需要谨慎对待,因为它只考虑查询成本,不考虑更新成本,要定期审查和删除那些很少被使用(通过sys.dm_db_index_usage_stats查看)或功能重复的冗余索引,因为每个索引都会降低INSERT、UPDATE、DELETE的速度。
关注统计信息的更新
统计信息是查询优化器估算成本、选择执行计划的依据,如果统计信息过时,优化器就像拿着旧地图找路,很容易走错,虽然SQL Server有自动更新统计信息的功能,但在数据量变化剧烈(比如大批量导入数据)后,自动更新可能不及时或采样比例不足,这时需要手动更新统计信息(UPDATE STATISTICS),阿里云开发者社区的经验是,对于核心大表,在大型ETL作业之后,手动更新一下统计信息是一个非常好的习惯。
审视数据库和表的设计 有些性能问题根源于设计阶段,后期优化事倍功半。
- 不合理的字段类型:用VARCHAR(MAX)存储只有几个字符的代码,用NVARCHAR存储纯英文内容,这些不必要的空间浪费会减少单页能存放的数据行数,导致IO增加。
- 滥用触发器:复杂的触发器会在不经意间大幅增加单条DML语句的执行时间,且问题难以排查。
- 过度规范化:将表拆得过于细碎,导致简单的查询也需要连接七八个表,连接成本本身就会很高,在某些对查询性能要求极高的场景下,适度的反规范化(如增加冗余字段)是必要的。
让SQL Server跑得更快,不仅需要知道那些“高大上”的调优技术,更需要持续关注这些日常开发中容易忽略的细微之处,养成良好的编程和运维习惯,这些细节的改进,累积起来往往能带来意想不到的性能提升。
本文由歧云亭于2026-01-12发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/79104.html
