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