我在我的C#项目中使用System.Data.SQLite
和SQLiteDataReader
。当获取附加数据库查询结果时,我面临着性能问题。
这里有一个搜索两个数据库中文本的查询示例:
ATTACH "db2.db" as db2;
SELECT MainRecord.RecordID,
((LENGTH(MainRecord.Value) - LENGTH(REPLACE(UPPER(MainRecord.Value), UPPER("FirstValueToSearch"), ""))) / 18) AS "FirstResultNumber",
((LENGTH(DB2Record.Value) - LENGTH(REPLACE(UPPER(DB2Record.Value), UPPER("SecondValueToSearch"), ""))) / 19) AS "SecondResultNumber"
FROM main.Record MainRecord
JOIN db2.Record DB2Record ON DB2Record.RecordID BETWEEN (MainRecord.PositionMin) AND (MainRecord.PositionMax)
WHERE FirstResultNumber > 0 AND SecondResultNumber > 0;
DETACH db2;
当使用SQLiteStudio或SQLiteAdmin执行此查询时,这很好,我可以在几秒钟内获得结果(记录表可能包含数十万条记录,查询返回36000条记录)。
当在我的C#项目中执行此查询时,执行也需要几秒钟,但要运行所有结果需要数小时。
以下是我的代码:
// Attach databases
SQLiteDataReader data = null;
using (SQLiteCommand command = this.m_connection.CreateCommand())
{
command.CommandText = "SELECT...";
data = command.ExecuteReader();
}
if (data.HasRows)
{
while (data.Read())
{
// Do nothing, just iterate all results
}
}
data.Close();
// Detach databases
调用
SQLiteDataReader
的Read
方法一次可能需要超过10秒!我猜这是因为SQLiteDataReader
是惰性加载的(因此在读取结果之前它不会返回整个行集),我是对的吗?编辑1:
我不知道这是否与惰性加载有关,就像我最初说的那样,但我想要的是在查询结束时能够立即获取所有结果。这不可能吗?在我看来,这真的很奇怪,一个在几秒钟内执行的查询需要花费数小时才能获得结果...
编辑2:
我只是在我的选择查询中添加了一个
COUNT(*)
,以便在第一个data.Read()
时能够看到是否可以获得总结果数,只是为了确保只是迭代结果需要这么长时间。但我错了:这个新的请求在SQLiteAdmin / SQLiteStudio中在几秒钟内执行,但在我的C#项目中需要几个小时。为什么相同的查询在我的C#项目中执行时间如此之长?编辑3:
通过使用
EXPLAIN QUERY PLAN
,我注意到在SQLiteAdmin / SQLiteStudio和我的C#项目中,相同查询的执行计划存在轻微差异。在第二种情况下,它在DB2Record上使用了一个AUTOMATIC PARTIAL COVERING INDEX
而不是使用主键索引。有没有办法忽略/禁用自动部分覆盖索引的使用?我知道它用于加速查询,但在我的情况下,相反地发生了...谢谢。
SQLiteDataReader
对象的ExecuteSingleQuery
方法。这就是为什么我在完成读取器之前处理命令。这样做是错误的吗? - Morgan M.using
而不是手动调用Close()
,以确保即使发生异常也会调用Close()
。 - Eldritch Conundrum