sql server索引视图要求所有表达式必须确定性:给定相同输入始终返回相同输出,否则create view(含schemabinding)即失败;非确定性函数如getdate()、newid()、未标记deterministic的udf等均被禁止。

SQL Server 不支持“物化视图”这个术语,它实际对应的是 索引视图(Indexed View)。而索引视图要求底层 SELECT 逻辑必须是确定性的——这不是设计偏好,而是 SQL Server 强制的存储与查询优化前提。
为什么非确定性函数会导致索引视图创建失败
SQL Server 在创建 CREATE UNIQUE CLUSTERED INDEX 到视图上时,会将视图结果物理持久化到磁盘。如果视图中包含 GETDATE()、NEWID()、ISNULL()(在某些排序上下文中)、或用户自定义函数(UDF)未显式标记为 DETERMINISTIC,SQL Server 无法保证同一查询在不同时间点产生完全相同的行集和排序顺序,也就无法维护索引键的稳定性。
典型错误信息:Cannot create index on view 'xxx' because it contains one or more nondeterministic functions.
-
GETDATE()、SYSDATETIME()、NEWID()、NEWSEQUENTIALID()直接禁止出现在索引视图定义中 -
ISNULL()和COALESCE()行为不等价:当用于连接列或索引键列时,COALESCE()可能触发隐式类型转换,导致非确定性比较;ISNULL()类型由第一个参数决定,更可控,但依然需确保参与列本身可排序且无隐式转换 - 自定义函数必须用
WITH SCHEMABINDING+ 显式声明DETERMINISTIC(通过EXEC sp_executesql N'ALTER FUNCTION ... WITH EXECUTE AS OWNER'等方式无法绕过)
确定性 ≠ 业务语义稳定,而是 SQL Server 内部可验证的表达式属性
一个表达式是否被 SQL Server 认为是确定性的,取决于其是否满足严格的技术条件:给定相同输入(含数据类型、NULL 性、排序规则),始终返回相同输出(含数据类型、长度、精度、标量值或 NULL)。例如:
-
LEN('abc')是确定性的;DATALENGTH(@var)在变量类型固定时也是,但如果 @var 是sql_variant且值动态变化类型,则可能被判定为非确定性 -
CONVERT(int, '123')是确定性的;但CONVERT(int, some_column)若该列存在隐式转换风险(如 varchar 含非数字字符),即使运行时不报错,仍可能被拒绝建索引 -
LEFT(col, 5)是确定性的;但若col是text或ntext(已弃用),则整个表达式不可索引
常见误判场景:看似静态,实则不可索引
开发者常以为“没用时间函数就安全”,但以下情况仍会触发非确定性检查失败:
- 视图定义中引用了没有
SCHEMABINDING的表或函数——即使内容不变,SQL Server 无法锁定依赖关系,视为潜在不稳定 - 使用了
ORDER BY子句(索引视图不允许)或TOP(除非配合WITH TIES和唯一约束,否则结果集不可重现) - 聚合列未包含所有
GROUP BY列,或HAVING中使用了非确定性谓词(如CHECKSUM(*) > 0) - 数据库兼容级别低于 120(SQL Server 2014+)时,部分原本确定的表达式(如某些日期计算)会被降级识别为非确定性
最易被忽略的一点:索引视图的确定性校验发生在 CREATE VIEW 阶段(带 WITH SCHEMABINDING),而非建索引时。也就是说,你甚至无法走到 CREATE UNIQUE CLUSTERED INDEX 这一步,只要视图定义里埋了一个 GETUTCDATE(),就会被立即拦截。










