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" 欄位定義的排序順序傳回所有列。這是預設的預期行為。如果虛擬表格以排序順序輸出所有列,則 xBestIndex 方法設定 "orderByConsumed" 旗標永遠是安全的,無論 sqlite3_vtab_distinct() 的傳回值為何。
如果 sqlite3_vtab_distinct() 介面傳回 1,則表示查詢規劃器不需要以排序順序傳回列,只要所有在 "aOrderBy" 欄位識別的所有欄位中具有相同值的列都相鄰即可。當查詢規劃器執行 GROUP BY 時,會使用此模式。
如果 sqlite3_vtab_distinct() 介面傳回 2,則表示查詢規劃器不需要以任何特定順序傳回列,只要所有在 "aOrderBy" 欄位識別的所有欄位中具有相同值的列都相鄰即可。此外,當兩個或多個列在 "colUsed" 識別的所有欄位中包含相同的值時,可以選擇從結果中省略除其中一列以外的所有列。虛擬表格不需要省略在 "colUsed" 欄位重複的列,但如果虛擬表格可以輕鬆做到這一點,則可能會幫助查詢更快地執行。此模式用於 DISTINCT 查詢。
如果 sqlite3_vtab_distinct() 介面傳回 3,則表示虛擬表格必須以 sqlite3_vtab_distinct() 介面傳回 0 時定義的 "aOrderBy" 順序傳回列。但是,如果結果中的兩個或多個列在 "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" 旗標,否則可能會導致錯誤的答案。
虛擬表格實作(virtual table implementation)可以自由決定傳回資料列的順序,只要「orderByConsumed」旗標未設定即可。當「orderByConsumed」旗標未設定時,查詢規劃器(query planner)會新增額外的位元組碼(bytecode),以確保 SQL 查詢傳回的最終結果排序正確。「orderByConsumed」旗標和 sqlite3_vtab_distinct() 介面的使用僅僅是一種最佳化。謹慎地使用 sqlite3_vtab_distinct() 介面和「orderByConsumed」旗標可能有助於提升查詢虛擬表格的速度。另一方面,過於積極地在不適用的情況下設定「orderByConsumed」旗標可能會導致 SQLite 傳回錯誤的結果。