Azure SQL托管实例非聚集索引间歇性不被使用问题求助
检查统计信息自动更新阈值
Azure SQL托管实例的统计信息自动更新逻辑和本地SQL Server存在差异,大表场景下默认阈值可能触发不及时。可以先关闭目标表的自动统计更新:sp_autostats 'YourLargeTableName', 'OFF'
然后手动制定更新计划,比如每天执行一次全量统计更新:UPDATE STATISTICS YourLargeTableName WITH FULLSCAN, NORECOMPUTE
也可以用sp_updatestats配合过滤,只针对大表做高频更新。强制索引使用(临时应急)
如果确认目标索引是最优选择,直接在查询里强制指定:SELECT * FROM YourLargeTableName WITH (FORCEINDEX(YourNonClusteredIndexName)) WHERE YourCondition
这招能快速解决当前查询性能问题,但只是临时方案,得从根源解决执行计划的问题。用Query Store分析执行计划变化
打开Azure SQL托管实例的Query Store,对比索引正常和失效时的执行计划,重点看预估行数和实际行数的差距。如果差得远,要么是统计信息过时,要么是参数嗅探在搞鬼。
要是参数嗅探的问题,给查询加OPTION (RECOMPILE),让SQL每次生成适配当前参数的计划:SELECT * FROM YourLargeTableName WHERE YourCondition OPTION (RECOMPILE)排查内存分配与查询内存授予
虽然升了内存,但Azure SQL托管实例的内存是动态分配的,可能存在查询内存不够导致计划变更的情况。用sys.dm_exec_query_memory_grants视图查一下相关查询的内存授予情况,要是经常出现内存压力,要么升级实例规格,要么优化查询减少内存需求。调整索引维护频率
10亿条的大表,索引碎片可能涨得很快,碎片多了索引效率就降了,SQL自然会换执行计划。定期查碎片率:SELECT name, avg_fragmentation_in_percent FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID('YourLargeTableName'), NULL, NULL, 'DETAILED')
碎片率超30%就重建,10%-30%就重组,把维护频率从每周改成每2天一次试试。核对数据库兼容性级别
确保Azure上的数据库兼容性级别和本地一致,比如本地是2019级(150),Azure也得设成一样的。查当前级别:SELECT compatibility_level FROM sys.databases WHERE name = 'YourDatabaseName'
改级别:ALTER DATABASE YourDatabaseName SET COMPATIBILITY_LEVEL = 150
内容的提问来源于stack exchange,提问作者Ranjit Singh

