我创建了一个SQLlite模式,如下所示:
CREATE TABLE tab1 (
year INTEGER,
tar_id TEXT,
content BLOB,
UNIQUE (year, tar_id) ON CONFLICT REPLACE);
CREATE INDEX tab1_ix1 ON bcas (year, tar_id);
然后,我查看了一个查询计划:
sqlite> explain query plan select * from tab1 where tar_id = 1 and year = (select max(year) from tab1 where year < 2019 and tar_id = 1);
QUERY PLAN
|--SEARCH TABLE tab1 USING COVERING INDEX sqlite_autoindex_tab1_1 (year=? AND tar_id=?)
`--SCALAR SUBQUERY
`--SEARCH TABLE tab1 USING COVERING INDEX tab1_ix1 (year<?)
在我看来,只有一个索引足以完成此操作,但是它同时使用了我的显式tab1_ix1
和自动生成的sqlite_autoindex_tab1_1
。
其中之一是多余的吗?如果是这样,我如何摆脱其中之一并获得相同的行为?
答案 0 :(得分:2)
是的,您有一个冗余索引。 unique
约束自动生成索引。您无需以相同的顺序为相同的列创建另一个显式索引。
请注意,(tar_id, year)
上的索引将是不同的索引,因为索引中键的顺序很重要。
答案 1 :(得分:0)
尽管两个接缝都是多余的,但仍有一些细节需要重点关注。在查询的第一部分中使用“ *”,因此自动创建的候选项最适合,因为它链接了所有其他列以进行检索。在第二部分的“ max”子句中,仅考虑了两列(年份,tar_id),它们均以所需的顺序出现在手动创建的“较小”索引“ tab1_ix1”中,并且引擎认为较小的效率高,因此这次使用了tab1_ix1
因此,如果可以承受轻微的性能下降,并且第二个较小的tab1_ix1似乎负担较重,那么引擎将使用默认的自动创建索引。