Reputation: 2941
I have a complex C# program that uses dynamically built queries to read from a SQLite database. I notice when I run the program under the debugger, I get lots of output like:
SQLite warning (284): automatic index on MyTable(Id)
I have looked at the schema for MyTable, and Id is specified as the primary key, like this:
CREATE TABLE MyTable (Id varchar(50) collate nocase primary key not null,
Name varchar(50) not null,
(etc)
I thought SQLite made indexes for primary keys anyway, so why is it making another one?
Also, on a related note, I get a lot of automatic index warnings about sub-queries. For instance, on the query:
SELECT MyTable.Id, MyTable.Name, Amount
FROM MyTable
LEFT JOIN (SELECT ArrangementId, Amount, AgreementDate FROM SubTable
JOIN Organisations ON Organisations.Id = SubTable.OrganisationId AND Organisations.Direction = 1
) AS MyJoin ON MyJoin.ArrangementId = MyTable.Id
ORDER BY Id
Where
MyTable has Id as the primary key
Organisations has Id as the primary key
SubTable has a unique index on ArrangementId, OrganisationId
EXPLAIN QUERY PLAN on the query yields:
1|0|0|SCAN TABLE SubTable
1|1|1|SEARCH TABLE Organisations USING INDEX sqlite_autoindex_Organisations_1 (Id=?)
0|0|0|SCAN TABLE Arrangements USING INDEX sqlite_autoindex_Arrangements_1
0|1|1|SEARCH SUBQUERY 1 AS MyJoin USING AUTOMATIC COVERING INDEX (ArrangementId=?)
I guess SQLite isn't clever enough to realise that the subquery does not need to go into a temporary table?
Is there any way of rewriting the query so a subquery is avoided?
Upvotes: 2
Views: 1274
Reputation: 180070
A collate nocase
column results in a collate nocase
index. That index cannot be used if the lookup does not use the same collation.
(Comparisons with that column use nocase
by default, but this does not help when the comparison is against another column with a different collation.)
If this query is important, consider creating a second index with the correct collation.
In the second query, the database must evaluate the subquery using a temporary table because it is the right operand of a left outer join (rule 3).
You could try to rewrite the query as a series of simple joins, if you're sure that the meaning stays the same:
FROM MyTable
LEFT JOIN SubTable ON MyTable.Id = SubTable.ArrangementId
LEFT JOIN Organisations ON Organisations.Id = SubTable.OrganisationId
AND Organisations.Direction = 1
Upvotes: 2
Reputation: 2062
Try making the following changes:
A few notes:
MyTable
and moving the varchar to a separate column with a unique constraint will make no difference to the size of MyTable
. As I mention above, the primary key column will be an alias for internal rowid column, so you aren't really adding any new columns.Upvotes: 0