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


8

我正在尝试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

产量

SCAN TABLE Player USING COVERING INDEX Player_FirstName

这正是我所期望的。查询计划人员认为,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

产量

SCAN TABLE PlayerJ USING INDEX PlayerJ_FirstName

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

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

Answers:


2

文件说:

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

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

与使用普通索引相比,使用覆盖索引与使用普通索引进行搜索/排序相比并没有多大改善,因此完全没有针对索引使用这种优化(至今?)。


在WHERE和/或ORDER BY语句中使用JSON_EXTRACT表达式是等效的,因为我只是使用SELECT字段创建了别名。重写查询以使用JSON_EXTRACT代替别名不会产生不同的结果。
Hozuki
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.