2

私はこの問題を解決するのに本当に苦労しています。次のコードを使用して多数のレコードのデータベースを更新すると、実行速度が非常に遅くなります。更新するレコードが500,000あり、これには1時間近くかかります。この操作中、ジャーナルファイルはメインの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が更新ごとに1つ作成してコミットすると思います...したがって、速度が遅くなります。コードを見ると、「Begin」コマンドと「End」コマンドを使用しても同じ結果が得られるかどうかはわかりません。すべてをラップするのではなく、開始時と終了時に空のトランザクションが発生する可能性があります。念のため、代わりに次のようなものを試してください。

  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)。

_knownFilessにforループがあります(double sで意図されていますか?)、それはおそらくゆっくり実行できますか?DBに対してforループでクエリを実行するのは珍しいことですが、それぞれのパラメータセットを使用してクエリを作成する必要があります。(特にハッシュにインデックスがない場合)n * mの操作を実行することを考慮してください(nはforループの実行カウント、mはテーブルサイズ)。

mが約500kであり、m = nであると仮定すると、250,000,000,000回の操作が可能になります。それは1時間続くかもしれません。

私の知る限り、以前の接続や操作は効果がないはずです。

また、データベースの内部構造が問題を引き起こしていないことを確認する必要があります。この操作の影響を受ける複合インデックスはありますか?外部キー/複雑な制約はありますか?

于 2012-05-15T09:37:19.163 に答える