sql server 默认不走索引视图索引,因优化器会自动展开视图;必须显式使用 with (noexpand) 提示才能强制利用其物化结果,且需满足 schemabinding、ansi_nulls=on 等严格条件。

为什么直接查索引视图不走索引
SQL Server 默认会“展开”(expand)索引视图,也就是把视图定义里的 SELECT 语句原样内联进主查询,再由优化器重写执行计划——此时它看到的是底层几张基表,而不是你辛苦建好的那个物化结果。哪怕视图上已有唯一聚集索引,只要没加提示,优化器就可能完全忽略它,继续跑一堆 Hash Join。
这不是 bug,是设计行为:索引视图默认只在查询“恰好匹配其定义”的情况下才可能被自动匹配(需满足 ANSI_NULLS=ON 等严格 SET 条件),而绝大多数业务查询都达不到这个精度。
必须用 WITH (NOEXPAND) 才生效
WITH (NOEXPAND) 是唯一能强制 SQL Server 把索引视图当“物理表”看待的提示。它告诉优化器:“别展开,就查这个视图本身,用它的索引。”
常见错误写法:
-
SELECT * FROM my_indexed_view WHERE ...—— 没提示,大概率展开 -
SELECT * FROM my_indexed_view NOEXPAND WHERE ...—— 缺WITH(),语法报错 -
SELECT * FROM my_indexed_view WITH (INDEX(pk_my_view))——INDEX提示对视图无效,只支持NOEXPAND
正确写法:
SELECT COUNT(*) FROM sales_summary_view WITH (NOEXPAND) WHERE order_date >= '2026-01-01';
不加 NOEXPAND 的后果很隐蔽
没加提示时,执行计划里看不到视图名,只有原始基表;IO 和 CPU 消耗跟没建视图前几乎一样。但你不会收到任何警告或错误——它只是安静地绕过了你的优化努力。
尤其要注意多层嵌套场景:如果 A 视图引用了 B 索引视图,你在查 A 时加 WITH (NOEXPAND),B 仍会被展开(NOEXPAND 不穿透)。必须在每层真正需要物化结果的地方显式加。
容易被忽略的前置条件
即使写了 WITH (NOEXPAND),以下任一条件不满足,提示也会静默失效(不报错,但不生效):
- 视图创建时没用
WITH SCHEMABINDING - 当前会话的
ANSI_NULLS或ANSI_WARNINGS是 OFF(SSMS 新建查询默认 ON,但某些 ORM 或旧客户端可能设为 OFF) - 视图中引用的基表与视图不同所有者(比如
dbo.orders和sales.vw_summary所有者不一致) - 查询中用了视图定义之外的列,或 WHERE 条件无法下推到视图定义的过滤逻辑内
验证是否真生效,最简单方法是看执行计划:节点名称里必须出现视图名(如 sales_summary_view),且其属性里显示“Storage: Structure is a clustered index”,而不是一堆基表名。










