加入收藏 | 设为首页 | 会员中心 | 我要投稿 站长网 (https://www.xcrb.com/)- 应用程序、AI行业应用、CDN、低代码、区块链!
当前位置: 首页 > 站长学院 > MsSql教程 > 正文

SQL Server查询卡顿?5个索引优化技巧提速3倍

发布时间:2026-11-09 11:12:01 所属栏目:MsSql教程 来源:DaWei
导读:  2025年6月,凌晨一点零七分,IDC机房那台老空调又开始间歇性喘气——咔、咔、停三秒、咔两声,跟SQL Server的CXPACKET等待堆栈一模一样。我盯着SSMS里跑着的执行计划,光标悬在“聚集索引扫描”那块红色粗箭头上,没点下去

  2025年6月,凌晨一点零七分,IDC机房那台老空调又开始间歇性喘气——咔、咔、停三秒、咔两声,跟SQL Server的CXPACKET等待堆栈一模一样。我盯着SSMS里跑着的执行计划,光标悬在“聚集索引扫描”那块红色粗箭头上,没点下去。王磊在群里甩来一张截图:/api/v3/search?tag=tech&offset=1840&limit=20,耗时四百一十三毫秒,P99飘到八百二。他加了个捂脸表情包,尾巴还带个小火苗????。


  我原以为是统计信息没更新——毕竟上回update statis是上周四下午三点十二分,我亲手敲的,连with fullscan都加了。结果sp_updatestats跑完,查询还是卡在Index Seek下面那个Nested Loops,左边是Users表,右边是UserTags(带WHERE IsActive=1 AND TenantId=@p1)。我删掉UserTags上那个覆盖索引,重建时手抖多按了个INCLUDE,把CreatedDate也塞进去了——这玩意儿压根没被SELECT用,但索引页大小愣是涨了百分之六点七。监控这时候跳了一条报警:SQLSERVER:Access Methods\\Page Splits/sec > 127。不是阈值设错了,是它真劈开了。


  第一个技巧?别建非必要INCLUDE。我敢打包票,去年双十一前夜,CDN缓存穿透打进来三千并发,我们查用户画像慢得像读磁带,最后发现主键索引上INCLUDE了七个字段,其中三个是varchar(500)的JSON碎片——全为“方便以后加筛选条件”。后来砍掉两个,QPS从一百四十七跳到三百七十二。但第三个要不要砍?我说不准。陈工说那个TagPath字段迟早要上搜索,我回他:“你上次说‘迟早’是去年七月,当时你们还在用MongoDB接蜘蛛爬虫。”


文章配图,仅供参考

  第二个:别信“复合索引字段顺序按WHERE顺序排”这种话。我们有个OrderItems表,WHERE里常写ProductId = @p1 AND IsShipped = 0 AND CreatedTime > @p2。大伙儿建索引都是(ProductId, IsShipped, CreatedTime)——看着顺眼。结果某天线上突然查慢,执行计划显示走的是(ProductId, CreatedTime, IsShipped)这个旧索引(是三年前迁移时遗留的),而新索引被优化器无视了。为啥?因为IsShipped只有两个值,等价于没筛选性。统计信息里distinct count=2,密度直插地心。我把顺序换成(CreatedTime, ProductId),再加个IsShipped在最后当过滤器,响应时间压回十八秒以内。可那个旧索引至今没删,备案系统还在扫它——谁动谁背锅,这规矩你懂。


  工位右下角那盒冷掉的黄焖鸡,米饭表面结了层膜。我拿筷子尖戳了戳,没戳破。手机震了一下,运营李薇@我问“明天上午十点能配合推新版API吗”,我没回。她昨天还问我“索引是不是像CDN缓存,越堆越多越好”,我当场笑出声,隔壁组张伟探头问“笑啥”,我摇头,继续看那个执行计划里的Key Lookup图标——小红叉叠着小红叉,像极了我们备案号后缀的四位随机码。


  第三个:UNIQUE约束不等于索引可用性。我们有个Tokens表,TokenHash字段加了UNIQUE约束,自动生成唯一索引。但某次审计发现,TokenHash是SHA2_256哈希值,长度六十四,而索引键最大只能九百字节。SQL Server偷偷把它转成nonclustered索引,但B树层级深了三层。有次凌晨批量签发令牌,INSERT速度直接掉到七十TPS,DBA查出来是页拆分风暴。后来手动删掉约束索引,重建为CLUSTERED + INCLUDE(TokenData, ExpiresAt),才稳住。但这个事儿现在没人提了——上个月张伟升主管,他说“只要不影响收录就行”。


  第四个:别怕DROP_EXISTING。我们有个老表ArticleSearch,上面六个索引,三个名字带_v2_v3_v4,全是不同人、不同时期建的,字段重叠率百分之八十一。我写了脚本逐个DROP_EXISTING重建,中间断了两次——一次是运维重启了AG副本同步,一次是我自己把WITH (ONLINE=ON)错打成ONLIEN。重跑第三遍时,咖啡洒在键盘F键上,之后三天我敲“FROM”都要多按一下Shift。但重建后,同一条全文模糊查(LIKE '%云原生%')从平均二百零四毫秒降到六十一毫秒。至于那些废弃索引到底占多少空间?我说不准。没人清过日志文件增长量,只看事务日志备份大小,上周五比前周五少了四百一十MB——可能是,也可能只是巧合。


  第五个,也是最反常识的:有时候,删索引比加索引快。上礼拜五下午,我盯了三小时,就是弄不明白为什么一个简单JOIN会触发RID Lookup。查了半天发现,目标表没主键,只有两个非唯一索引,而查询里用了WHERE Status IN (1,2,3) AND UpdatedAt > GETDATE()-7。优化器选了那个UpdatedAt索引,然后疯狂回表。我手抖把Status索引删了——瞬间走聚集扫描,反而快了。这不是玄学,是SQL Server在没有统计信息支撑时的保底策略:宁可全扫,也不瞎跳。王磊说“这违反直觉”,我说:“直觉是留给做PPT的人的。”他回了个狗头,后面跟着一串省略号……


  其实最该干的事,是翻出三个月前那版建库脚本,把所有nvarchar(max)字段改成varchar(800),再删掉那个叫“Archive_Flag_For_Wechat_Compat”的bit字段——它从来就没被用过,连CMS后台都不认这个标记。但昨晚运维发了个公告:“核心库暂不接受结构变更申请,除非走一级灰度流程”。所以我今早点了杯冰美式,打开Excel,打算把所有未使用索引列个表。咖啡凉了。空调又开始咔、咔、停三秒。


  对了,刚才李薇又@我,这次发了个文档链接,标题叫《新版API接口兼容性核验清单_V2.1_final_edited_by_PMO》。我点了收藏,没点开。

(编辑:站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!