我有一个复杂的C#程序,它使用动态构建的查询从SQLite数据库中读取。 我注意到当我在调试器下运行程序时,我得到了很多输出,如:
SQLite warning (284): automatic index on MyTable(Id)
我查看了MyTable的架构,并将Id指定为主键,如下所示:
CREATE TABLE MyTable (Id varchar(50) collate nocase primary key not null,
Name varchar(50) not null,
(etc)
我认为SQLite无论如何都为主键创建了索引,为什么还要制作另一个?
另外,在相关的说明中,我收到了很多关于子查询的自动索引警告。例如,在查询上:
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
其中
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产生:
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=?)
我猜SQLite不够聪明,不知道子查询不需要进入临时表吗?
有没有办法重写查询以避免子查询?
答案 0 :(得分:1)
collate nocase
列会产生collate nocase
索引。如果查找不使用相同的排序规则,则无法使用该索引。
(默认情况下,与该列的比较使用nocase
,但当比较针对具有不同排序规则的其他列时,这无效。)
如果此查询很重要,请考虑使用正确的排序规则创建第二个索引。
在第二个查询中,数据库必须使用临时表评估子查询,因为它是左外连接(rule 3)的右操作数。
如果你确定含义保持不变,你可以尝试将查询重写为一系列简单连接:
FROM MyTable
LEFT JOIN SubTable ON MyTable.Id = SubTable.ArrangementId
LEFT JOIN Organisations ON Organisations.Id = SubTable.OrganisationId
AND Organisations.Direction = 1
答案 1 :(得分:0)
尝试进行以下更改:
一些注意事项:
MyTable
中使用INTEGER PRIMARY KEY并将varchar移动到具有唯一约束的单独列,这对MyTable
的大小没有影响。如上所述,主键列将是内部rowid列的别名,因此您并不真正添加任何新列。