确定性函数和非确定性函数

适用于:SQL ServerAzure SQL 数据库Azure SQL 托管实例Microsoft Fabric 中的 SQL 分析终结点Microsoft Fabric 中的仓库Microsoft Fabric 预览版中的 SQL 数据库

只要使用特定的输入值集并且数据库具有相同的状态,那么不管何时调用,确定性函数始终都会返回相同的结果。 即使访问的数据库状态保持不变,非确定函数每次使用一组特定的输入值调用时,都可能会返回不同的结果。 例如,该函数 AVG 始终返回与前面所述的限定项相同的结果,但 GETDATE 返回当前日期/时间值的函数始终返回不同的结果。

有多个用户定义函数的属性,这些属性通过调用函数的计算列索引或通过引用函数的索引视图来确定 SQL Server 数据库引擎为函数的结果建立索引的功能。 函数的确定性是一个属性。 例如,假设某个视图引用了任何非确定性函数,则无法对该视图创建聚集索引。 有关函数的属性的详细信息,包括确定性,请参阅 用户定义的函数

确定性函数必须是架构绑定的。 创建确定性函数时,请使用 SCHEMABINDING 子句。

本文介绍了内置系统函数的确定性,以及在包含对扩展存储过程的调用时对用户定义函数的确定性的影响。

确定函数是否具有确定性

可以通过查询函数的 is_deterministic 对象属性来检查函数是否为确定性的。 以下示例确定函数 Sales.CalculateSalesTax 是否具有确定性。

SELECT OBJECTPROPERTY(OBJECT_ID('Sales.CalculateSalesTax'), 'IsDeterministic');

内置函数的确定性

用户无法影响任何内置函数的确定性。 每个内置函数都是确定性的或不确定的,具体取决于 SQL Server 实现函数的方式。 例如,在 ORDER BY 查询中指定子句不会更改该查询中使用的函数的确定性。

FORMAT 外,所有字符串内置函数都是确定性的。 有关这些函数的列表,请参阅 字符串函数

内置函数类别中除字符串函数以外的下列内置函数始终具有确定性。

  • ABS
  • ACOS
  • ASIN
  • ATAN
  • ATN2
  • CEILING
  • COALESCE
  • COS
  • COT
  • DATALENGTH
  • DATEADD
  • DATEDIFF
  • DAY
  • DEGREES
  • EXP
  • FLOOR
  • ISNULL
  • ISNUMERIC
  • LOG
  • LOG10
  • MONTH
  • NULLIF
  • POWER
  • RADIANS
  • ROUND
  • SIGN
  • SIN
  • SQRT
  • SQUARE
  • TAN
  • YEAR

下列函数并非始终是确定性函数,但是在以确定性方式指定后,可用于索引视图或计算列的索引。

函数 注释
所有聚合函数 除非使用 and OVER 子句指定ORDER BY所有聚合函数,否则所有聚合函数都是确定性的。 有关这些函数的列表,请参阅 聚合函数
CAST 除非与 datetimesmalldatetimesql_variant一起使用,否则其他时候都是确定性的。
CONVERT 除非存在下列条件,否则为确定性函数:

源类型是 sql_variant

目标类型是 sql_variant ,其源类型不是确定性的。

源类型或目标类型是 datetimesmalldatetime,其他源类型或目标类型是字符串,并且指定了不确定的样式。 若要为确定样式,则样式参数必须是常量。 此外,除了样式 20 和 21,小于或等于 100 的样式都具有不确定性。 大于 100 的样式具有确定性,但样式 106、107、109 和 113 除外。
CHECKSUM 确定性,除 CHECKSUM(*).
ISDATE 仅当与函数一起使用 CONVERT 时, CONVERT 才指定样式参数,并且样式不等于 0、100、9 或 109。
RAND RAND 仅在指定 种子 参数时确定性。

所有配置、游标、元数据、安全和系统统计函数都是非确定性函数。 可以看到这些函数的列表

其他类别中的下列内置函数始终为非确定性函数。

  • @@CONNECTIONS
  • @@CPU_BUSY
  • @@DBTS
  • @@IDLE
  • @@IO_BUSY
  • @@MAX_CONNECTIONS
  • @@PACKET_ERRORS
  • @@PACK_RECEIVED
  • @@PACK_SENT
  • @@TIMETICKS
  • @@TOTAL_ERRORS
  • @@TOTAL_READ
  • @@TOTAL_WRITE
  • AT TIME ZONE
  • CUME_DIST
  • CURRENT_TIMESTAMP
  • DENSE_RANK
  • FIRST_VALUE
  • FORMAT
  • GETDATE
  • GETUTCDATE
  • GET_TRANSMISSION_STATUS
  • LAG
  • LAST_VALUE
  • LEAD
  • MIN_ACTIVE_ROWVERSION
  • NEWID
  • NEWSEQUENTIALID
  • NEXT VALUE FOR
  • NTILE
  • PARSENAME
  • PERCENTILE_CONT
  • PERCENTILE_DISC
  • PERCENT_RANK
  • RAND
  • RANK
  • ROW_NUMBER
  • TEXTPTR

从函数中调用扩展存储过程

由于扩展存储过程会对数据库产生副面影响,因此调用扩展存储过程的函数为不确定性函数。 副作用是对数据库的全局状态(例如对表的更新)或外部资源(例如文件或网络)的更改。 示例包括修改文件或发送电子邮件。 从用户定义函数中执行扩展存储过程时,不要依赖于返回一致的结果集。 建议不要使用对数据库产生负面影响的用户定义函数。

从函数内部调用扩展存储过程时,该扩展存储过程不能向客户端返回结果集。 任何向客户端返回结果集的 Open Data Services API 都有返回代码 FAIL

扩展存储过程可以连接回 SQL Server。 但是,该过程不能与调用扩展存储过程的原始函数联接同一事务。

与批处理或存储过程的调用类似,扩展存储过程在运行 SQL Server 的 Windows 安全帐户的上下文中执行。 扩展存储过程的所有者在授予其他用户执行该过程的权限时,应该考虑此安全性上下文的权限。