SQLite C 接口
确定虚拟表查询是否为 DISTINCT
int sqlite3_vtab_distinct(sqlite3_index_info*);
此 API 只能在虚拟表实现的xBestIndex 方法 中使用。从 xBestIndex() 外部调用此接口的结果是未定义的,并且可能有害。
sqlite3_vtab_distinct() 接口返回一个介于 0 和 3 之间的整数。sqlite3_vtab_distinct() 返回的整数为虚拟表提供了有关查询计划程序希望如何对输出进行排序的附加信息。只要虚拟表能够满足查询规划器的排序要求,它就可以设置“orderByConsumed”标志。
如果 sqlite3_vtab_distinct() 接口返回 0,这意味着查询计划器需要虚拟表以 sqlite3_index_info对象的“nOrderBy”和“aOrderBy”字段定义的排序顺序返回所有行。这是默认的期望。如果虚拟表按排序顺序输出所有行,那么无论 sqlite3_vtab_distinct() 的返回值如何,xBestIndex 方法设置“orderByConsumed”标志始终是安全的。
如果 sqlite3_vtab_distinct() 接口返回 1,这意味着查询规划器不需要按排序顺序返回行,只要在“aOrderBy”字段标识的所有列中具有相同值的所有行都是相邻的。当查询规划器执行 GROUP BY 时使用此模式。
如果 sqlite3_vtab_distinct() 接口返回 2,这意味着查询规划器不需要以任何特定顺序返回的行,只要所有“aOrderBy”列中具有相同值的行都是相邻的。此外,对于由“aOrderBy”字段标识的列中的每个特定值组合,只需要返回一行。返回所有“aOrderBy”列中具有相同值的两行或更多行总是可以的,只要所有这些行都是相邻的。虚拟表可以,如果它选择,忽略额外的行,这些行对于由“aOrderBy”标识的所有列具有相同的值。然而,省略额外的行是可选的。此模式用于 DISTINCT 查询。
如果 sqlite3_vtab_distinct() 接口返回 3,这意味着查询规划器只需要不同的行,但它确实需要对行进行排序。如果愿意,虚拟表实现可以自由地省略所有 aOrderBy 列中相同的行,但不需要省略任何行。此模式用于同时具有 DISTINCT 和 ORDER BY 子句的查询。
为了比较虚拟表输出值以查看这些值是否是相同的值以进行排序,两个 NULL 值被认为是相同的。换句话说,比较运算符是“IS”(或“IS NOT DISTINCT FROM”)而不是“==”。
如果一个虚拟表实现不能满足上面指定的要求,那么它不能在 sqlite3_index_info对象中设置“orderByConsumed”标志,否则可能会导致错误的答案。
只要未设置“orderByConsumed”标志,虚拟表实现总是可以按任意顺序自由返回行。当“orderByConsumed”标志未设置时,查询计划器将添加额外的 字节码以确保 SQL 查询返回的最终结果被正确排序。“orderByConsumed”标志和 sqlite3_vtab_distinct() 接口的使用仅仅是一种优化。仔细使用 sqlite3_vtab_distinct() 接口和“orderByConsumed”标志可能有助于对虚拟表的查询运行得更快。另一方面,过于激进并在无效时设置“orderByConsumed”标志可能会导致 SQLite 返回不正确的结果。