Reputation:
I created an SQLlite schema as follows:
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);
Then I looked at a query plan:
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<?)
It seems to me that only one index would be sufficient to do this, but it uses both my explicit tab1_ix1
and and automatically generated sqlite_autoindex_tab1_1
.
Is one of them redundant? If so, how do I get rid of one of them and get the same behaviour?
Upvotes: 0
Views: 77
Reputation: 1269873
Yes, you have a redundant index. A unique
constraint generates an index automatically. You do not need to create another one explicitly index for the same columns in the same order.
Note that an index on (tar_id, year)
would be a different index, because the ordering of keys in the index matters.
Upvotes: 2
Reputation: 29
Although both seam redundant but there is some detail to be focused. In first part of query "*" is used so the auto created candidate is best suited because it links all other columns to retrieve. While in second portion with "max" clause only two columns (year, tar_id) are under consideration and they are all present with needed sequence in "smaller" manually created index "tab1_ix1" and engine thinks smaller being efficient so it uses tab1_ix1 this time.
So the default auto created index will be utilized by engine if slight degradation in performance is affordable and second smaller tab1_ix1 seem burden maintenance wise.
Upvotes: 0