【问题标题】:SqLite C# extremely slow on updateSqlLite C# 更新速度极慢
【发布时间】:2012-05-15 09:26:44
【问题描述】:

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

【问题讨论】:

  • mhash 列上是否有索引?
  • 'CatItem CatItem' 与您的命名不一致。而是使用'var catItem'。它只是提高了可读性(本地人的大小写)

标签: c# sqlite executenonquery journal


【解决方案1】:

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

或[插入]

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

【讨论】:

  • 问题是在 mhash 上缺少索引。我以为我有一个,但在建议后仔细检查,发现我没有!我添加了一个索引,我的表现已经飙升!非常感谢大家的建议 - 这让我发疯了!
【解决方案2】:

您需要将所有内容包装在事务中,否则我相信 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();
  } 

【讨论】:

    【解决方案3】:

    这部分肯定是你的问题。

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

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

    【讨论】:

      【解决方案4】:

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

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-02-16
        • 2015-07-22
        • 1970-01-01
        • 1970-01-01
        • 2015-02-07
        • 2011-03-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多