使用C#SQLite DataReader和附加数据库迭代结果的性能问题
我在我的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:
我刚刚在我的select查询中添加了一个COUNT(*)
,以便查看是否可以在第一个data.Read()
获得结果总数,只是为了确保它只是结果的迭代太长。 我错了:这个新请求在几秒钟内在SQLiteAdmin / SQLiteStudio中执行,但在我的C#项目中执行需要几个小时。 知道为什么同一个查询在我的C#项目中执行的时间要长得多吗?
编辑3:
感谢EXPLAIN QUERY PLAN
,我注意到SQLiteAdmin / SQLiteStudio和我的C#项目之间的同一查询的执行计划略有不同。 在第二种情况下,它在DB2Record上使用AUTOMATIC PARTIAL COVERING INDEX
而不是使用主键索引。 有没有办法忽略/禁用自动部分覆盖索引的使用? 我知道它用于加速查询,但在我的情况下,它发生了相反的情况……
谢谢。
除了查找匹配记录外,您似乎还在计算字符串匹配的次数。 此计数的结果也在WHERE
子句中使用。
您需要匹配数,但WHERE
子句中的匹配数无关紧要 – 您可以尝试将WHERE
子句更改为:
WHERE MainRecord.Value LIKE '%FirstValueToSearch%' AND DB2Record.Value LIKE '%SecondValueToSearch%'
它可能不会产生任何差异 – 特别是如果Value
列上没有索引 – 但值得一试。 文本列上的索引需要很多空间,所以我不会盲目推荐。
如果还没有这样做,请在DB2的RecordID
列上放置一个索引。
您可以使用EXPLAIN QUERY PLAN SELECT ...
使SQLite吐出它尝试使您的查询执行的function,其输出可能有助于诊断问题。
您确定在System.Data.SQLite
,SQLiteStudio和SQLiteAdmin中使用相同版本的sqlite吗? 你可以有很大的差异。
SQL查询在使用ADO.NET和本机实用程序(如SQLiteAdmin)执行时可能需要不同时间的一个典型原因是CommandText中使用的命令参数(从代码中不清楚是否使用了参数)。 根据ADO.NET提供程序实现,以下相同的CommandText值:
SELECT * FROM sometable WHERE somefield = ? // assume parameter is '2'
和
SELECT * FROM sometable WHERE somefield='2'
可能导致完全不同的执行计划和查询性能。
另一个建议:您可以禁用日志(在连接字符串中指定“日志模式=关闭;”)和同步模式(“同步=关闭;”),因为在某些情况下这些选项也可能会影响查询性能。