2

パフォーマンスに問題がありますSQLite database (.db)

データベース (.db) の 1,00,000 レコードを更新しようとしていますが、これには約 50 分かかります。遅すぎる。

私のコードは以下のようなものです::

        for (int q = 0; q < list.Count; q++) 
            { 
        ArrayList castarraylist = new ArrayList(); 
        castarraylist = (ArrayList)(list[q]); 

        using (var cmd = new SQLiteCommand(con)) 

            using (var transaction = con.BeginTransaction()) 
            { 
                cmd.Transaction = transaction; 

                for (int y = 0; y < castarraylist.Count; y++) 
                { 
                        cmd.CommandText = Convert.ToString(castarraylist[y]); 
                           cmd.ExecuteNonQuery(); 
                } 
                transaction.Commit(); 
                GC.Collect(); 
            } 
        } 

ここでは、各 castarraylist に 5000 レコードが含まれています。トランザクションでデータベースに更新するもの。ということで20回ループして更新完了。時間を手動で確認している間、5000 レコードの反復ごとに時間を増やしています。お気に入り

1st 5000 records processing time > 1:11 minute

2nd 5000 records processing time > 1:25 minute

3rd  5000 records processing time > 1:32 minute 

4th 5000 records processing time > 1:40 minute 

5th 5000 records processing time > 1:47 minute 

6th 5000 records processing time > 1:52 minute 

...

... 

... 

17th 5000 records processing time > 3:32 minute 

18th 5000 records processing time > 3:44 minute

19th 5000 records processing time > 4:02 minute 

20th 5000 records processing time> 4:56 minute 

なぜこれが起こったのか、私には理解できません。私のソースコードは C# で書かれており、ラップトップの構成はi5 2.6 GHz, 4 GB RAM,500 GB HDです。

以下のように接続しました::

SQLiteConnection con = new SQLiteConnection("Data Source=" + fullPath + ";Version=3;Count Changes=off;Journal Mode=off;Pooling=true;Cache Size=10000;Page Size=4096;Synchronous=off"); 

(*フルパス - 私のデータベースパスです)

以下のようなテーブルを作成しています...

sqlquery2="Select LINK_ID from RDF_LINK string createLinkToPoly = "create table temp2 AS " + sqlquery2;

これにより、テーブルが作成され、sqlquery2 によって取得されるレコードが挿入されます。

以下のステートメントは、SQLite で Spatialite を拡張します

ExecuteStatement("select load_extension('spatialite.dll')", con);

私のUpdate声明は以下のようなものです::

UPDATE temp2 SET GEOM = Transform(LineStringFromText('LINESTRING(4.38368 51.18109,4.38427 51.18165)',4326),32632)WHERE LINK_ID= 53841546

この種の 100000 ステートメントは、異なるスレッドで構築され、挿入されますLIST

最後UPDATEに上記のコードでステートメントを実行します(現在、Larryが提案したコードを使用しています)

4

4 に答える 4

3

まず、パフォーマンスを向上させるために、準備済みステートメントを使用してみてください。SQLiteParameterSystem.Data.SQLite のドキュメントを参照して、ループでパラメーター値を使用および設定できるようにします。

第二に、または配列ArrayListよりも遅くする必要があります。List多分それを変えることは助けになるかもしれません。

第 3 に、使用できるプラグマ コマンドがいくつかある場合があります。

編集:既に同期とジャーナルモードをオフにしているようですが、他に使用すべきプラグマがあるかどうかはわかりません。場合によっては、locking_mode = EXCLUSIVE および temp_store = MEMORY が役立つことがあります。

于 2014-07-04T07:38:24.207 に答える
3

現在、トランザクションはクエリごとに実行されますが、これは意味がありません。

メイン ループ コードをトランザクションで囲み、この GC.Collect() を削除します。

編集:

私が理解しているように、エラーが発生した場合にグローバル更新がロールバックされることは望ましくありません。ということで、コードを少し変更。

さらに、CommandText を変更してクエリを再度実行することで、コマンド オブジェクトを再利用できるかどうかもわかりません。そのため、毎回作成することをお勧めします。

using (var transaction = con.BeginTransaction()) 
{ 
    for (int q = 0; q < list.Count; q++) 
    { 
        var castarraylist = (ArrayList)(list[q]); 

        for (int y = 0; y < castarraylist.Count; y++) 
        { 
            using (var cmd = new SQLiteCommand(con)) 
            {
                cmd.Transaction = transaction; 
                cmd.CommandText = Convert.ToString(castarraylist[y]);
                try
                {
                    cmd.ExecuteNonQuery();
                }
                catch(Exception ex)
                {
                    // Log the update problem
                    Console.WriteLine("Update problem " + cmd.CommandText + " - Reason: " + ex.Message);
                }
            }
        }
    }

    transaction.Commit();
}
于 2014-07-04T07:45:05.853 に答える
2

おそらく、SQLite でパフォーマンスの問題は発生していません。ほぼ確実に、独自のコードでパフォーマンスの問題が発生しています。

  • GC.Collect() を呼び出す必要はほとんどありません。ここで行っていることは、重大なメモリ プレッシャを引き起こしているべきではありません。そうである場合は、問題を強制するのではなく、ガベージ コレクタに任せることを強くお勧めします。さらに悪いことに、 loop のすべての反復でGC.Collect() を呼び出しています。これをしないでください!

  • 個々の更新をそれぞれ独自のトランザクションで行うことが本当に必要ですか? このループの途中でコードが失敗して例外がスローされた場合、前半の更新はコミットされていますが、中断したところから再開する方法がないことを認識していますか? どこで中断したかを知る簡単な方法さえありません。

  • List<T> ではなく ArrayList を使用している特定の理由はありますか? これにより、内部ループでキャストを実行して Convert.ToString を呼び出す必要がありますが、これは必要ありません (ArrayList を使用する非常に正当な理由がない限り)。

于 2014-07-04T10:11:27.870 に答える