SCHEMABINDING 是 SQL Server 强制要求用于索引视图的绑定机制,以锁定依赖对象结构、确保数据一致性;不加则无法创建唯一聚集索引,且需两段式引用、确定性表达式及严格函数限制。

SCHEMABINDING 是什么,为什么必须加
SQL Server 的 indexed view 必须带 SCHEMABINDING,否则根本建不了唯一聚集索引。这不是可选项,是引擎强制要求——因为 indexed view 的物理数据要和基表保持强一致性,SQL Server 需要通过 schema binding 锁定所依赖的表、列、函数定义,防止后续有人改表结构(比如删列、改类型)导致索引数据逻辑错乱或查询失败。
常见错误:Cannot create index on view 'dbo.vSalesSummary' because the view is not schema-bound.
- 声明 view 时必须写
WITH SCHEMABINDING,且所有引用对象(表、函数)都要用两段式名称,比如dbo.Sales,不能只写Sales - 不能引用临时表、表变量、TVF(除非是内联 TVF 且也带 SCHEMABINDING)、系统视图或跨库对象
- 如果基表上有计算列,该列表达式也必须满足 deterministic(确定性),否则
SCHEMABINDING会拒绝创建
indexed view 能用哪些函数和表达式
不是所有 SQL 写法都能放进 indexed view。SQL Server 对 deterministic 和 precision 有严格限制,否则无法保证索引数据在不同执行路径下一致。
- 禁止非确定性函数:
GETDATE()、NEWID()、@@ROWCOUNT、HOST_NAME()等直接报错 -
ISNULL()可用,但COALESCE()在部分旧版本中可能被判定为 non-deterministic(尤其含子查询时),建议统一用ISNULL() - 聚合必须包含
GROUP BY所有非聚合列,且不能漏掉GROUP BY中的列(比如写了SELECT a, SUM(b) FROM t GROUP BY a是合法的;但漏掉a或多加未分组列就失败) - 不能用
TOP、ROW_NUMBER()、窗口函数、UNION ALL(除非所有分支都满足 indexed view 规则且无重复列名)
为什么查询不走 indexed view 的索引
即使你成功建好了带唯一聚集索引的 view,查询也不一定自动命中它。SQL Server 查询优化器默认“忽略” indexed view,除非显式启用或满足严苛条件。
- 默认情况下,只有查询语义**完全匹配** view 定义(列、过滤、连接方式、聚合逻辑)时才可能重写使用,实际中几乎不可靠
- 最稳妥的方式是加
WITH (NOEXPAND)提示:SELECT * FROM dbo.vSalesSummary WITH (NOEXPAND)。不加这个,哪怕 view 上有索引,也可能被展开成底层表扫描 - 如果查询里用了
ANSI_NULLS OFF或QUOTED_IDENTIFIER OFF,view 就不可用(建 view 时这两个 SET 选项必须为 ON,且查询上下文也要一致) - 数据库兼容级别低于 120 时,某些优化规则不生效,
NOEXPAND行为也可能异常
性能收益与隐藏代价
indexed view 确实能加速特定聚合/连接场景,但代价常被低估:维护开销、锁粒度、存储膨胀。
- 每次更新基表,SQL Server 必须同步更新 indexed view 的索引页——写放大明显,尤其高并发 UPDATE/INSERT 场景下,可能拖慢主业务
- view 索引会参与锁升级,一个
UPDATE基表行可能同时持基表行锁 + view 索引页锁,死锁风险上升 - 存储占用翻倍常见:比如基表 10GB,view 加了唯一聚集索引后又占 8–12GB,且不能压缩(除非用 COLUMNSTORE,但那是另一套规则)
- 统计信息独立于基表,容易过期;必须定期更新 view 的统计信息:
UPDATE STATISTICS dbo.vSalesSummary
真正值得上 indexed view 的场景其实很窄:读远多于写、聚合逻辑固定、结果集相对稳定、且能接受写入延迟。盲目套用,反而让系统更难调优。











