3

在测试我们的SQLite Virtual Table机制实现过程中,我们遇到了意外的行为。对于以下virtual table结构:

create table X(ID int, RL real)

此查询按 RL 字段以正确的降序返回所有记录。

查询 1

select * from VTab t1 left outer join VTab t2 on t1.ID = t2.ID order by t1.RL desc;

执行计划一

explain query plan select * from VTab t1 left outer join VTab t2 on t1.ID = t2.ID order by t1.RL desc;  

0|0|0| SCAN TABLE VTab AS t1 VIRTUAL TABLE INDEX 0:D1; (~0 rows)
0|1|1| SCAN TABLE VTab AS t2 VIRTUAL TABLE INDEX 4:C0=0; (~0 rows)

D1这是我们的xBestIndex方法实现生成的值,表示按字段 #1 = RL 降序排序C0=0这里意味着字段 #0 = ID 的相等操作。这按预期工作。

但是,下一个查询返回行(RL字段的别名不同)而不进行任何排序。

查询 2

select * from VTab t1 left outer join VTab t2 on t1.ID = t2.ID order by t2.RL desc

执行计划2

explain query plan select * from VTab t1 left outer join VTab t2 on t1.ID = t2.ID order by t2.RL desc;  

0|0|0| SCAN TABLE VTab AS t1 VIRTUAL TABLE INDEX 0: (~0 rows)
0|11| SCAN TABLE VTab AS t2 VIRTUAL TABLE INDEX 4:C0=0; (~0 rows)

如您所见,没有提到要排序的索引。针对真实表(与我们的虚拟表具有完全相同的结构)执行的查询如下所示:

查询 3

select * from Table1 t1 left outer join Table1 t2 on t1.ID = t2.ID order by t2.RL desc

执行计划3

explain query plan select * from Table1 t1 left outer join Table1t2 on t1.ID = t2.ID order by t2.RL desc;  

0|0|0| SCAN TABLE Table1 AS t1 (~1000000 rows)
0|1|0| SEARCH TABLE Table1 AS t2 USING AUTOMATIC COVERING INDEX (ID=?)
0|1|0| (~7 rows)
0|0|0| USE TEMP B-TREE FOR ORDER BY

如您所见,使用B-tree那里进行排序。

在我们这边,我们检查了我们在sqlite3_index_orderby结构(结构的一部分sqlite3_index_info)中收到的内容,当它们出现时xBestIndex,它们不包含任何关于排序的信息。out 参数也orderByConsumed返回 False(因为我们的输出没有排序,我们假设本身会对行进行排序)。

这是SQLite Virtual Table支持中的错误还是我们错过了什么?

4

2 回答 2

2

正如评论中allocateIndexInfo()所说,只有“ORDER BY 子句仅包含当前虚拟表中的列”时,您的虚拟表才有机会实现排序。在您的查询中,排序列来自的虚拟表仅用于查找 ID 列,并且单个值的此类查找不可用于排序。


使用 SQLite 3.7.14,我在查询 2 的计划中确实得到了“USE TEMP B-TREE FOR ORDER BY”。xBestIndex 返回的值是什么?

于 2012-09-16T10:52:00.890 回答
2

The reason of the problem lied in improper handling of the orderByConsumed output flag value.

For this query with JOIN, our xBestIndex implementation returned orderByConsumed = True for the index that matched ON condition, which actually wasn't correct because no ordering was done in that case. This disregarded any further ORDER BY clause members.

After the fix orderByConsumed started return True only for the indexes where nOrderBy flag was greater than 0 and False otherwise.

于 2012-09-19T16:16:01.117 回答