SQLite 中的 SQL 函数可以是“确定性”或“非确定性”。
确定性函数在输入相同的情况下始终给出相同的答案。大多数 SQLite 内置 SQL 函数都是确定性的。例如,abs(X) 函数只要其输入 X 相同,就始终返回相同的答案。
非确定性函数在每次调用时可能给出不同的答案,即使参数始终相同。以下是非确定性函数的示例
random() 函数显然是非确定性的,因为它每次调用时都会给出不同的答案。来自 changes() 和 last_insert_rowid() 的答案取决于先前的 SQL 语句,因此它们也是非确定性的。 sqlite3_version() 函数大多数情况下是恒定的,但它可能会在 SQLite 升级时发生变化,因此即使它在任何特定会话中始终返回相同的答案,因为它可以在会话之间更改答案,因此它仍然被认为是非确定性的。
SQLite 中有一些上下文不允许使用非确定性函数
在以上情况下,函数返回的值会影响数据库文件中存储的信息。CHECK 约束中函数的值决定了哪个条目对表有效,而部分索引的 WHERE 子句或表达式索引中的函数计算存储在索引 b 树中的值。如果这些函数中的任何一个稍后返回不同的值,那么数据库可能不再是良好的格式。因此,为了避免数据库损坏,只有确定性函数可以在上述上下文中使用。
SQLite 的内置 日期和时间函数 是一种特殊情况。这些函数通常被认为是确定性的。但是,如果这些函数使用字符串“now”作为日期,或者如果它们使用 localtime 修饰符 或 utc 修饰符,那么它们将被视为非确定性的。因为函数输入在运行时不一定已知,所以如果日期/时间函数在仅允许使用确定性函数的上下文中遇到任何非确定性特征,它们将抛出异常。
在 SQLite 3.20.0(2017-08-01)之前,所有日期/时间函数都始终被认为是非确定性的。日期/时间函数有时是确定性的,有时是非确定性的,具体取决于它们的参数,这种能力是在 3.20.0 版本中添加的。
当对 SQLite 3.20.0 进行增强,使日期/时间函数被认为是确定性的,因为它们不依赖于当前时间时,有一个情况被忽略了:许多日期/时间函数可以被完全不带参数地调用。这些无参数日期/时间函数的行为就像它们有一个单独的“'now'" 参数。因此“datetime()" 和 “datetime('now')" 都产生当前日期和时间。但是,只有第二种形式被识别为非确定性的。这意味着开发人员可以将非确定性的“datetime()" 形式偷偷插入 CHECK 约束、索引表达式、生成列表达式以及类似的地方,在这些地方,非确定性函数毫无意义。这种疏忽在版本 3.35.2(2021-03-17)中得到了修复。但是,可能存在由 SQLite 版本 3.20.0 到 3.35.1 创建的已流传的旧版数据库,这些数据库在其模式中包含非确定性日期/时间函数。
默认情况下,应用程序定义的 SQL 函数 被认为是非确定性的。但是,如果 sqlite3_create_function_v2() 的第 4 个参数与 SQLITE_DETERMINISTIC 进行 OR 运算,那么 SQLite 将把该函数视为确定性函数。
请注意,如果一个非确定性函数被标记为 SQLITE_DETERMINISTIC,并且如果该函数最终被用于 部分索引 的 WHERE 子句或 表达式索引 中,那么当该函数开始返回不同的答案时,关联的索引可能会损坏。如果一个 SQL 函数几乎是确定性的(也就是说,如果它很少改变,比如 sqlite_version()),并且它被用于一个损坏的索引中,则可以通过运行 REINDEX 来修复损坏。
构造一个函数,根据其输入有时是确定性的,有时是非确定性的,比如内置的日期/时间函数,所需的接口没有公开。通用 应用程序定义的 SQL 函数 必须始终是确定性的或始终是非确定性的。
此页面上次修改于 2022-01-08 05:02:57 UTC