我有一个C#应用程序,使用SQLite作为数据库,使用SQLite Entity Framework 6提供程序根据用户输入生成查询语句。
数据库包含以下表和索引:
CREATE TABLE Lists (
ListRowId INTEGER NOT NULL PRIMARY KEY,
ListId GUID NOT NULL,
ListName TEXT NOT NULL
);
CREATE UNIQUE INDEX [IX_Lists_ListId] ON [Lists] ( [ListId] );
-- One to many relationship: Lists => ListDetails
CREATE TABLE ListDetails (
ListDetailRowId INTEGER NOT NULL PRIMARY KEY,
ListDetailId GUID NOT NULL,
ListId GUID NOT NULL,
Plate TEXT
);
CREATE INDEX [IX_ListDetails_Plate] ON [ListDetails] ( [Plate] ASC );
CREATE TABLE Reads (
ReadRowId INTEGER NOT NULL PPRIMARY KEY,
ReadId GUID NOT NULL,
Plate TEXT
);
-- 1 To many relationship: Reads => Alarms.
-- There may be rows in Reads that have no related rows in Alarms.
CREATE TABLE Alarms (
AlarmRowId INTEGER NOT NULL PPRIMARY KEY,
AlarmId GUID NOT NULL,
ListId GUID NOT NULL,
ListDetailId GUID NOT NULL,
ReadRowId INTEGER NOT NULL
);
CREATE INDEX [IX_Alarms_ListId_ListDetailId] ON [Alarms] ([ListId], [ListDetailId]);
CREATE INDEX [IX_Alarms_ReadId] ON [Alarms] ([ReadRowId]);
请注意,上面的DDL仅包括相关列和索引。由于
ListDetails
表中行数众多且为了提高速度,ListDetailId
GUID列上没有索引,也无法创建。事实上,我不能更改数据库模式。数据库中没有定义这些表之间的任何外键关系。原因是我们系统内部的问题。我重申,我不能更改模式。
使用SQLite EF6提供程序,我从数据库构建了一个实体模型。它是一个数据库优先模型,因为应用程序最初是使用不同的数据库和EF 4编写的。我们将其升级到EF 6并用SQLite替换了数据库。
在处理用户输入时,我必须组合一个查询,连接这些表。以下是我构建的基本EF表达式。
from read in context.Reads
join alrm in context.Alarms on read.ReadRowId equals alrm.ReadRowId into alarmJoin
from alarm in alarmJoin.DefaultIfEmpty()
join e in context.ListDetails on alarm.ListPlate equals e.Plate into entryJoin
from entry in entryJoin.DefaultIfEmpty()
join l in context.Lists on alarm.ListId equals l.ListId into listJoin
from list in listJoin.DefaultIfEmpty()
where alarm.ListDetailId = entry.ListDetailId
select new {
alarm,
list.ListName,
read
};
我使用调试器获取了该表达式并生成了SQL语句。为了简洁起见,我已经减少了输出内容,因为我只关心在ListDetails
表上的连接:
SELECT *
FROM [Reads] AS [Extent1]
LEFT OUTER JOIN [Alarms] AS [Extent2] ON [Extent1].[ReadRowId] = [Extent2].[ReadRowId]
LEFT OUTER JOIN [ListDetails] AS [Extent3] ON ([Extent2].[ListPlate] = [Extent3].[Plate]) OR (([Extent2].[ListPlate] IS NULL) AND ([Extent3].[Plate] IS NULL))
LEFT OUTER JOIN [Lists] AS [Extent4] ON [Extent2].[ListId] = [Extent4].[ListId]
WHERE ([Extent2].[ListDetailId] = [Extent3].[ListDetailId]) OR (([Extent2].[ListDetailId] IS NULL) AND ([Extent3].[ListDetailId] IS NULL))
执行 EXPLAIN QUERY PLAN 后,结果显示此查询将对 ListDetails 表进行表扫描。我不希望这种情况发生;我希望查询使用 Plate 列上的索引。
如果我删除 where 子句,则生成的 SQL 不同:
SELECT *
FROM [Reads] AS [Extent1]
LEFT OUTER JOIN [Alarms] AS [Extent2] ON [Extent1].[ReadRowId] = [Extent2].[ReadRowId]
LEFT OUTER JOIN [ListDetails] AS [Extent3] ON ([Extent2].[ListPlate] = [Extent3].[Plate]) OR (([Extent2].[ListPlate] IS NULL) AND ([Extent3].[Plate] IS NULL))
LEFT OUTER JOIN [Lists] AS [Extent4] ON [Extent2].[ListId] = [Extent4].[ListId]
这个查询的EXPLAIN QUERY PLAN显示数据库确实使用了ListDetails
表的Plate
列上的索引。 这正是我想要的结果。 但是,ListDetails
表中可能会有多行具有相同的Plate
;它不是唯一的字段。 我需要返回与Alarms
表中提供的信息匹配的唯一一行。
如何使我的查询使用Plate
列上的索引?