我真的很难解决这个问题。当我使用以下代码更新我的数据库以获取大量记录时,它运行速度非常慢。我有500,000条记录要更新,这需要将近一个小时。在此操作期间,日志文件缓慢增长,主SQLite db3文件几乎没有变化 - 这是正常的吗?
当我有大量数据或记录要更新时,操作似乎只是一个问题 - 它几乎立即在较少数量的记录上运行。
在此代码运行之前,对数据库执行了一些其他操作,那么它们是否会占用数据库?我已经尝试确保所有其他连接都正确关闭。
感谢您的任何建议
using (SQLiteConnection sqLiteConnection = new SQLiteConnection("Data Source=" + _case.DatabasePath))
{
sqLiteConnection.Open();
using (SQLiteCommand sqLiteCommand = new SQLiteCommand("begin", sqLiteConnection))
{
sqLiteCommand.ExecuteNonQuery();
sqLiteCommand.CommandText = "UPDATE CaseFiles SET areaPk = @areaPk, KnownareaPk = @knownareaPk WHERE mhash = @mhash";
var pcatpk = sqLiteCommand.CreateParameter();
var pknowncatpk = sqLiteCommand.CreateParameter();
var pmhash = sqLiteCommand.CreateParameter();
pcatpk.ParameterName = "@areaPk";
pknowncatpk.ParameterName = "@knownareaPk";
pmhash.ParameterName = "@mhash";
sqLiteCommand.Parameters.Add(pcatpk);
sqLiteCommand.Parameters.Add(pknowncatpk);
sqLiteCommand.Parameters.Add(pmhash);
foreach (CatItem CatItem in _knownFiless)
{
if (CatItem.FromMasterHashes == true)
{
pcatpk.Value = CatItem.areaPk;
pknowncatpk.Value = CatItem.areaPk;
pmhash.Value = CatItem.mhash;
}
else
{
pcatpk.Value = CatItem.areaPk;
pknowncatpk.Value = null;
pmhash.Value = CatItem.mhash;
}
sqLiteCommand.ExecuteNonQuery();
}
sqLiteCommand.CommandText = "end";
sqLiteCommand.ExecuteNonQuery();
sqLiteCommand.Dispose();
sqLiteConnection.Close();
}
sqLiteConnection.Close();
}
答案 0 :(得分:2)
确保你有mhash索引的第一件事。 将命令分组到批次中。 使用多个线程。
或[插入]
批量导入记录到临时表。在mhash列上创建索引。执行单个更新语句以更新记录。
答案 1 :(得分:0)
这部分肯定是你的问题。
foreach (CatItem CatItem in _knownFiless)
{
....
sqLiteCommand.ExecuteNonQuery();
}
您正在循环List(?)并对数据库执行查询。这不是一个好方法。因为数据库调用非常昂贵。因此,您可以考虑使用其他方式更新这些项目。
答案 2 :(得分:0)
SQL代码似乎没问题。 C#代码没有错,但它有一些冗余(因为你已经使用了using
,所以不需要显式关闭/ dispose。)
_knownFiless上有一个for循环(打算用双s?),可能会慢慢运行吗?在针对数据库的for循环中运行查询是很常见的,而应该使用相应的参数集创建查询。考虑一下(特别是没有哈希索引)你将执行n * m次操作(n是for循环的运行次数,m是表的大小)。
考虑到m大约为500k,假设m = n,你将获得250,000,000,000次操作。这可能持续一个小时。
据我所知,以前的连接或操作应该没有效果。
您还应确保数据库的内部结构不会导致问题。是否存在受此操作影响的复合索引?任何外键/复杂的约束?
答案 3 :(得分:0)
你需要将所有东西都包装在一个事务中,否则我相信SQLite会为每次更新创建并提交一个...因此速度很慢。您清楚地知道查看您的代码但我不确定使用“开始”和“结束”命令在此处实现相同的结果,您可能最终在开始和结束时使用空事务而不是包装所有内容。尝试这样的事情,以防万一:
using (SQLiteTransaction mytransaction = myconnection.BeginTransaction())
{
using (SQLiteCommand mycommand = new SQLiteCommand(myconnection))
{
SQLiteParameter myparam = new SQLiteParameter();
mycommand.CommandText = "YOUR QUERY HERE";
mycommand.Parameters.Add(myparam);
foreach (CatItem CatItem in _knownFiless)
{
...
mycommand.ExecuteNonQuery();
}
}
mytransaction.Commit();
}