2

我真的很难解决这个问题。当我使用以下代码更新我的数据库以获取大量记录时,它的运行速度非常慢。我有 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();
}
4

4 回答 4

2

首先要确保您在 mhash 上有一个索引。将命令分组。使用多个线程。

或 [插入]

将记录批量导入临时表。在 mhash 列上创建索引。执行单个更新语句来更新记录。

于 2012-05-15T09:35:44.713 回答
1

这部分肯定是你的问题。

foreach (CatItem CatItem in _knownFiless)
{
....
     sqLiteCommand.ExecuteNonQuery();
}

您正在循环 List(?) 并对数据库执行查询。这不是一个好方法。因为数据库调用非常昂贵。因此,您可能会考虑使用另一种方式来更新这些项目。

于 2012-05-15T09:34:13.250 回答
1

您需要将所有内容包装在事务中,否则我相信 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();
  } 
于 2012-05-15T11:48:35.200 回答
0

SQL 代码似乎没问题。C# 代码没有错,但它有一些冗余(不需要显式关闭/处置,因为您已经在使用using)。

_knownFiles 上有一个 for 循环(用 double s 表示?),它可能运行缓慢吗?在 for 循环中针对 DB 运行查询是不常见的,您应该使用相应的参数集创建查询。考虑到(尤其是在哈希上没有索引)您将执行 n * m 操作(n 是 for 循环的运行计数,m 是表大小)。

考虑到 m 大约为 500k,并假设 m = n 您将获得 250,000,000,000 次操作。这可能会持续一个小时。

据我所知,以前的连接或操作应该没有影响。

您还应该确保数据库的内部结构不会引起问题。是否存在受此操作影响的复合索引?任何外键/复杂的约束?

于 2012-05-15T09:37:19.163 回答