前两天和一个做电商的朋友吃饭,他抱怨说后台系统一到促销活动就卡成PPT,查个订单要等半分钟。我问他数据库怎么搞的,他说是 SQL Server,没做什么优化,表里几百万条数据堆着跑。这场景太熟悉了——不是机器不够快,而是代码写得糙。今天咱们就聊聊怎么让 SQL Server 查询效率飙起来,别光盯着加索引,那只是入门功夫。

先说最基础的:索引不是越多越好,关键是会用。很多新手一上来就给所有字段建索引,结果写操作慢得像蜗牛。我见过一个案例,有个日志表每天插入几十万条数据,建了五六个索引后,插入速度直接掉了 80%。为啥?因为每插入一条数据,所有索引都得更新一次。正确做法是:针对高频查询的字段建索引,比如订单表的订单号、用户 ID,但别给那些只用来排序或很少出现在 WHERE 里的字段乱加。还有,复合索引比单列索引更香——如果你经常用 ,就建一个 的复合索引,顺序很重要,把区分度高的放前面,这样数据库能快速缩小数据范围,而不是傻乎乎地扫全表。
说到查询语句,很多人觉得写个 没啥问题,但实际查询时,字段越多,数据页读取量就越大。我调过的一个财务报表,原来用 查了 30 多个字段,业务只需要 5 个,改完后查询时间从 8 秒降到 1.2 秒。原理很简单:SQL Server 读取数据是按页来的,每页 8KB,字段多了就得读更多页,IO 压力自然大。另外,避免在 WHERE 里使用函数,比如 ,这会导致索引失效,数据库只能全表扫描。改成 ,索引就能用上,效率提升一个数量级。
执行计划是优化的照妖镜。我每次调优必先看执行计划,重点关注几个指标:扫描次数、查找操作、连接类型。如果看到 Table Scan 或者 Clustered Index Scan,说明索引没用好,大概率要加索引或改写语句。比如有个查询,执行计划显示 Hash Match 连接,这通常意味着两个表的数据量都不小,而且没有合适的索引支持。我在连接字段上加索引后,Hash Match 变成了 Nested Loops,查询从 5 秒降到 0.3 秒。别怕看执行计划,右键选“显示估计的执行计划”就能看到图形化界面,一目了然。要是看到 Key Lookup 操作多,说明索引覆盖不够,可以考虑建包含列索引,把查询需要的字段都塞进去,避免回表查数据页。
再讲个容易被忽视的点:统计信息。SQL Server 依靠统计信息来估计数据分布,从而选最优执行计划。如果统计信息过时,可能选错索引,明明有索引却去扫表。我碰过一个案例,一个表数据量从 100 万涨到 500 万,统计信息没更新,查询计划一直用老估计,导致效率暴跌。解决办法很简单:定期更新统计信息,或者设置自动更新阈值。默认是数据变化 20% 时自动更新,但大表可以手动调低阈值。更新命令是 ,别等到卡死了才想起这件事。另外,参数嗅探也是个坑——第一次执行时的参数值决定了缓存计划,后续参数不同可能不适用。解决办法是使用 强制重编译,或者用 让优化器使用平均估计。
连接查询是性能杀手,尤其是多表关联。我有次调一个 ERP 系统的报表,查了 6 张表,嵌套了 3 层子查询,跑了 18 秒。拆开一看,很多关联字段没有索引,而且用了 LEFT JOIN 但逻辑上其实不需要。优化思路:尽量用 INNER JOIN 替代 LEFT JOIN,后者会保留左表所有行,增加处理量。还有,子查询尽量换成 JOIN,SQL Server 对 JOIN 的优化比子查询好得多。比如把 改成 JOIN 写法,通常能快 30% 以上。如果实在要用子查询,确保子查询的表有索引,而且关联字段类型一致——隐式类型转换会让索引失效,比如 INT 和 VARCHAR 比较,数据库得先转换类型,索引就白建了。
说说硬件和配置。很多人觉得加内存、换 SSD 就万事大吉,但 SQL Server 的配置参数也得调。比如最大内存设置,默认会留一部分给操作系统,但如果服务器有 64 GB 内存,SQL Server 只用了 40 GB,那剩下的就是浪费。建议设成物理内存的 80% 左右,留点给 OS。还有一个参数是并行度(MAXDOP),默认 0 表示使用所有 CPU 核心,但高并行度可能导致内存争用。OLTP 系统建议设成 2 或 4,OLAP 系统可以高一些。另外,日志文件和数据文件要分开放在不同磁盘,减少 IO 竞争。我见过一个客户把日志和数据库放在同一盘,结果写日志和读数据抢 IO,查询慢得不行。分开后,效果立竿见影。
优化这事儿没有终点。你改了一条语句,可能今天快 10 倍,明天数据量翻倍又得调。关键是养成习惯:写完 SQL 先看执行计划,定期检查慢查询日志,用动态管理视图(DMV)监控性能瓶颈。比如 可以查哪些查询最耗资源, 能看索引使用情况。别等用户抱怨了才动手,那会儿黄花菜都凉了。把优化当成日常运维的一部分,你的 SQL Server 才能真正跑出十倍效率。


