视图查询慢的根本原因是未启用schemabinding导致无法创建索引,必须先用with schemabinding重建视图(补全两段式表名、禁用非确定性函数等),再建唯一聚集索引,并在查询中使用with (noexpand)提示才能生效。

视图查询慢,不是视图本身的问题,而是它背后没被优化的执行计划在拖后腿。直接加索引没用,必须先让视图“可索引”——也就是用 SCHEMABINDING 重建。
为什么 CREATE UNIQUE CLUSTERED INDEX 在视图上失败?
常见错误是执行 CREATE UNIQUE CLUSTERED INDEX idx_v ON dbo.MyView (id) 后报错:Cannot create index on view 'MyView' because the view is not schema bound. 或更长的“不满足索引视图要求”。这不是语法错,是视图定义不符合 SQL Server 的硬性前提。
- 视图必须用
WITH SCHEMABINDING创建,否则底层表结构一改,视图就可能失效,SQL Server 不允许这种风险 - 所有表名必须是两段式(如
dbo.Orders),不能写Orders或* - 不能含
GETDATE()、NEWID()、子查询、TOP、UNION、OUTER JOIN、非确定性函数 - 若含聚合(如
COUNT(*)),必须改用COUNT_BIG(*),且需配合GROUP BY
如何用 SCHEMABINDING 重建视图?
不能 ALTER VIEW 加 SCHEMABINDING,必须 DROP 后重建。重建前确认基表有主键或唯一非空约束(比如 Customers.CustomerID 和 Orders.OrderID)。
- 先查原视图定义:
SELECT OBJECT_DEFINITION(OBJECT_ID('dbo.MyView')) - 复制定义,开头加上
WITH SCHEMABINDING,所有表名补全 schema(如把Orders改成dbo.Orders) - 删掉
SELECT *,显式列出每列;删掉TOP、ORDER BY、计算列(除非函数是确定性的,如ISNULL(UnitPrice, 0)可以,但GETDATE()不行) - 执行重建语句,再试
CREATE UNIQUE CLUSTERED INDEX
建完索引视图,查询为什么还是不走它?
索引视图不会自动被所有查询命中。是否启用取决于版本和写法:
- 只有 Enterprise / Developer 版本才可能自动匹配(优化器判断成本更低时)
- Standard / Express 版本必须显式引用视图,并加
WITH (NOEXPAND)提示,例如:SELECT * FROM dbo.vw_SalesSummary WITH (NOEXPAND) WHERE ProductID = 123 - 外部查询的
WHERE条件列,必须包含在视图索引键中,否则仍会退化为扫描基表 - 执行计划里看到
Clustered Index Seek或Scan对应的是视图的索引名(如idx_vw_SalesSummary),才算真正用上了
容易被忽略的关键点
很多人以为建完索引视图就万事大吉,其实还有几个隐性门槛:
-
ANSI_NULLS和QUOTED_IDENTIFIER会话设置必须为 ON,否则创建或使用都会失败 - 统计信息不会自动更新,基表数据大幅变化后,得手动执行
UPDATE STATISTICS视图或其基表 - 索引视图会增加写操作开销(INSERT/UPDATE/DELETE 基表时要同步维护视图结果),读多写少场景才适合
- 视图定义一旦绑定,就不能删改底层表结构(比如删列、改类型),否则 DROP 视图前必须先 DROP 索引











