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”标识的所有列中具有相同值的行相邻即可。此外,当两个或多个行在“colUsed”标识的所有列中包含相同的值时,可以选择省略除其中一行以外的所有行。虚拟表不需要省略在“colUsed”列上重复的行,但是,如果虚拟表可以在不增加太多额外工作的情况下做到这一点,则可能会帮助查询更快地运行。此模式用于 DISTINCT 查询。
如果 sqlite3_vtab_distinct() 接口返回 3,则意味着虚拟表必须按“aOrderBy”定义的顺序返回行,就好像 sqlite3_vtab_distinct() 接口返回了 0 一样。但是,如果结果中的两个或多个行在“colUsed”标识的所有列中具有相同的值,则可以选择省略除其中一行以外的所有行。与返回值为 2 时一样,虚拟表不需要省略在“colUsed”列上重复的行,但是,如果虚拟表可以在不增加太多额外工作的情况下做到这一点,则可能会帮助查询更快地运行。此模式用于同时具有 DISTINCT 和 ORDER BY 子句的查询。
下表汇总了虚拟表根据 sqlite3_vtab_distinct() 返回的值设置“orderByConsumed”标志的允许条件。此表是对前四段的重述。
sqlite3_vtab_distinct() 的返回值 | 行按 aOrderBy 顺序返回 | 所有 aOrderBy 列中具有相同值的行相邻 | 可以省略所有 colUsed 列上的重复项 |
0 | 是 | 是 | 否 |
1 | 否 | 是 | 否 |
2 | 否 | 是 | 是 |
3 | 是 | 是 | 是 |
为了将虚拟表输出值进行比较以查看这些值是否具有相同的排序值,两个 NULL 值被视为相同。换句话说,比较运算符是“IS”(或“IS NOT DISTINCT FROM”),而不是“==”。
如果虚拟表实现无法满足上述要求,则它不得设置 sqlite3_index_info 对象中的“orderByConsumed”标志,否则可能会导致错误的答案。
虚拟表实现始终可以按任何它想要的顺序返回行,只要没有设置“orderByConsumed”标志即可。当“orderByConsumed”标志未设置时,查询规划器将添加额外的 字节码 以确保 SQL 查询返回的最终结果按正确顺序排序。“orderByConsumed”标志和 sqlite3_vtab_distinct() 接口的使用只是一个优化。谨慎使用 sqlite3_vtab_distinct() 接口和“orderByConsumed”标志可能会帮助针对虚拟表的查询更快地运行。另一方面,过度激进并在无效时设置“orderByConsumed”标志可能会导致 SQLite 返回错误的结果。