SQLite3 不使用带有 json_extract 表达式的覆盖索引

Dea*_*ike 8 sqlite index optimization execution-plan

我正在尝试SQLite3使用json_extract表达式在(3.18) 中创建索引。我的目标是执行只需要索引才能产生结果的查询。这样做的原因是这json_extract是一项昂贵的操作,在对较大的数据集和/或值进行操作时会影响性能。我得出结论,我需要一个覆盖索引来满足我的需求。

第 1 步 - 使用正常的表结构测试理论

CREATE TABLE Player (
    Id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    FirstName TEXT NOT NULL,
    MiddleName TEXT,
    LastName TEXT NOT NULL
);

CREATE INDEX Player_FirstName ON Player (
    FirstName ASC,
    LastName ASC
);

EXPLAIN QUERY PLAN SELECT
    FirstName, LastName
FROM
    Player
WHERE
    LENGTH(LastName) > 10
ORDER BY
    FirstName
LIMIT
    10
OFFSET
    0
Run Code Online (Sandbox Code Playgroud)

产量

SCAN TABLE Player USING COVERING INDEX Player_FirstName
Run Code Online (Sandbox Code Playgroud)

这正是我所期望的。Player_FirstName由于该ORDER BY子句,查询计划器认为索引是合适的,并且由于该WHERE语句仅对也在该索引中的值进行操作,因此不需要读取表。最后,SELECT声明只包括因此导致在不触及表的查询索引列在所有

第 2 步 - 使用提取表达式测试理论

CREATE TABLE PlayerJ (
    Id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    Data TEXT NOT NULL
);

CREATE INDEX PlayerJ_FirstName ON PlayerJ (
    JSON_EXTRACT(Data, '$.FirstName') ASC,
    JSON_EXTRACT(Data, '$.LastName') ASC
);

EXPLAIN QUERY PLAN SELECT
    JSON_EXTRACT(Data, '$.FirstName') AS FirstName,
    JSON_EXTRACT(Data, '$.LastName') AS LastName
FROM
    PlayerJ
WHERE
    LENGTH(LastName) > 10
ORDER BY
    FirstName
LIMIT
    10
OFFSET
    0
Run Code Online (Sandbox Code Playgroud)

产量

SCAN TABLE PlayerJ USING INDEX PlayerJ_FirstName
Run Code Online (Sandbox Code Playgroud)

不是我所期望的。查询规划器似乎已经发现该ORDER BY子句在 上JSON_EXTRACT(Data, '$.FirstName'),因此似乎已经选择了适当的索引。但这就是我的推理突然结束的地方。这里发生了什么?我本来希望查询计划器能够弄清楚这与之前的测试相同,并且该索引将用作覆盖索引。但事实并非如此。

为什么不?以及如何修改第二个测试以使其仅针对索引运行?

CL.*_*CL. 2

文档

当索引的表达式出现在查询的 WHERE 子句或 ORDER BY 子句中时,SQLite 查询计划程序将考虑在表达式上使用索引。

因此 SELECT 子句中的表达式不会使用表达式索引。

使用覆盖索引并没有比使用普通索引进行搜索/排序的改进大,因为使用普通索引优于根本不使用索引,因此这种优化尚未(还?)针对表达式索引实现。