创建索引视图必须使用SCHEMABINDING并显式指定两段式对象名,且需设置ANSI_NULLS等SET选项为ON(NUMERIC_ROUNDABORT为OFF),否则报错;查询时须加OPTION(NOEXPAND)提示才能强制使用索引视图。

CREATE VIEW 必须带 SCHEMABINDING 才能建索引视图
不加 SCHEMABINDING 的视图无法创建聚集索引,SQL Server 会直接报错:Cannot create index on view 'xxx' because the view is not schema bound.。这是硬性前提,不是可选项。
实际操作中容易漏掉两点:一是忘记在 CREATE VIEW 语句开头显式写上 WITH SCHEMABINDING;二是引用表时没带两段式名称(schema.table),比如写成 SELECT * FROM Students 而不是 SELECT * FROM dbo.Students,这也会导致 SCHEMABINDING 失效。
- 必须使用两段式对象名(如
dbo.Orders) - 不能用
SELECT *,所有列名需明确列出 - 不能引用临时表、表变量或 TVF(表值函数)
- 基础表不能有计算列(除非是确定性且持久化的)
创建聚集索引前要先满足 SET 选项要求
即使视图语法正确,执行 CREATE UNIQUE CLUSTERED INDEX 时仍可能失败,错误信息类似:Cannot create index on view. Required option SET ANSI_NULLS is OFF.。这是因为索引视图依赖一组严格的会话级 SET 设置,必须全部为 ON。
最稳妥的做法是在创建视图和索引前,显式设置这些选项——哪怕你确认当前会话已开启,也建议写死,避免跨工具(如 SSMS 新查询窗口 vs SQLCMD)行为不一致:
SET ANSI_NULLS ON; SET QUOTED_IDENTIFIER ON; SET ANSI_PADDING ON; SET ANSI_WARNINGS ON; SET CONCAT_NULL_YIELDS_NULL ON; SET NUMERIC_ROUNDABORT OFF;
注意:NUMERIC_ROUNDABORT 必须为 OFF,和其他几个相反,这点容易记反。
索引视图的更新机制与数据一致性保障
索引视图不是“自动刷新”的缓存,而是物化存储(即真实数据页),SQL Server 在基础表发生 INSERT/UPDATE/DELETE 时同步维护其内容。这意味着它天然强一致,但代价是写入性能下降 —— 尤其当视图涉及多表 JOIN 或聚合时,每次修改都触发复杂计算。
典型陷阱是误以为索引视图能替代应用层缓存。实际上,它更适合读远多于写的场景,比如报表汇总表、BI 层预计算宽表。如果基础表每秒更新上百次,而视图又含 COUNT(*) 或 SUM(),那聚集索引维护开销会非常可观。
- 基础表结构变更(如删列、改类型)会直接导致索引视图失效,必须先
DROP INDEX再DROP VIEW - 不能对索引视图执行
INSERT/UPDATE/DELETE(报错:View or function 'xxx' is not updatable) - 查询时若未启用
NOEXPAND提示,优化器可能选择绕过索引视图走底层表,失去加速效果
为什么查询时经常需要加 OPTION (NOEXPAND)
SQL Server 默认可能忽略索引视图,转而展开执行底层 JOIN 或聚合逻辑,尤其当统计信息陈旧或查询谓词不够匹配时。结果就是:明明建了索引视图,执行计划里却看不到对它的扫描,性能毫无提升。
强制使用索引视图的最可靠方式,是在查询末尾加上 OPTION (NOEXPAND):
SELECT OrderYear, TotalAmount FROM vw_OrderSummaryByYear WHERE OrderYear = 2024 OPTION (NOEXPAND);
这个提示告诉优化器:“别展开这个视图,就当我是一张物理表”。生产环境关键查询建议始终带上,否则索引视图很可能形同虚设。
另外,NOEXPAND 只对带聚集索引的视图有效;普通视图加了也没用。这点常被忽略,导致调试时反复怀疑语法或权限问题。










