2

データベースから 100 万件のレコードを読み取り、いくつかの処理後にレコードを別のテーブルに挿入するプログラムがあります。そのため、プログラムは DAO API を呼び出して 100 万件のレコードを取得し、メモリ内でループします。挿入も DAO API を使用して挿入を行います。各 DAO API パーツは次のように実装されます。

    public static void Main(string[] args)
    {
        List<TableA> tableAs = GetTableAs();
        TableB tableB = null;
        foreach (var tableA in tableAs) {
           tableB.id = tableA.id;
           // ...
           // here I copy/modify records from table A
           // ...
           InsertTableB(tableB);
        } 
    }

    public static List<TableA> GetTableAs()
    {
        using (var ctx = new TableDataContext())
        {
            var entities = from e in ctx.tableAs
                           select e;
            return new List<tableA>(entities);
        }
    }

    public static void InsertTableB(TableB tableB)
    {
        using (var ctx = new TableDataContext())
        {
            ctx.tableBs.InsertOnSubmit(tableB);
            ctx.SubmitChanges();
        }
    }

私のプログラムでは、500k の挿入後に「メモリ不足」の例外が発生しますが、非常に一貫しています。そして、ループ中にメモリ使用量が増加し続けることに気付きました。ガベージコレクションを強制しても、メモリを再利用することはできません。LINQ との対話に問題があるため、メモリが保持され、解放されません。どんな助けでも大歓迎です。

4

3 に答える 3

1

何よりもまず、そのコードの書き方を再考する必要があると思います.今のところ、それは非常に非効率的です.たとえば、毎回コンテキストを再作成します.1つのコンテキストだけを保持しないのはなぜですか?

さらに良いのは、単一の SQL ステートメントに書き直すことで、すべての手間が省けることです。

コンテキストの再作成は CPU にかなり負担がかかります。上記の例で示したように、必要な接続が 1 つだけの場合、複数回作成するとリソースが無駄になります。

次に、LINQ to SQL では、作成、編集、変更するすべてのオブジェクトで変更追跡が行われるため、どのオブジェクトを処理するかがわかります。そして、メモリの問題の原因になる可能性があります。

したがって、ObjectTrackingEnabled = false を使用して何が起こるかを確認することをお勧めします。

そして最後に、一括挿入をのぞいてみたいと思います。

于 2012-05-08T08:07:19.310 に答える
1

linq2sql を使用して 3000000 を超える行を挿入しようとしたときに、同じ問題に直面しました。700k の挿入後に OutOfMemoryException が発生していました。最後に、以前の DataContext を破棄し、100k 後に新しいものを作成し、追跡をオフにしません。

于 2015-05-13T14:39:47.127 に答える
0

問題は、おそらく .NET CLR のメモリ リークではなく、上記の LINQ to SQL コードの実行に必要な大量のメモリにあると考えられます。

最初にこの MSDN ブログ投稿を参照してください: http://blogs.msdn.com/b/tom/archive/2008/04/10/chat-question-memory-limits-for-32-bit-and-64-bit -processes.aspx

私はハードウェアの仕様を持っていないので、上記の記事のように 2800MB のメモリ制限を仮定します。

1,000,000 records <= 2800MB
1,000,000 records <= 23,488,102,400 bits
1 record <= 23488.1024 bits
1 record <= 2.8672KB

理論的には、これはテーブル A からメモリにコピーされる各レコードが 2.8672KB を超えてはならないことを意味します。

ただし、実際の値は通常、CLR に関連する他のオーバーヘッドにより低くなります。これは、500,000 レコードがテーブル A からディープ コピーされ、テーブル B に挿入された後にスローされる OutOfMemoryException に反映されます。

他の投稿者が示唆しているように、メモリに保持できるレコードの数を増やす方法があることは確かですが、表 A のレコードの数が増えると、問題が再び表面化する可能性が高くなります。

実行可能な代替手段は、おそらく、基になる SQL Server データベースにストアド プロシージャを作成し、代わりにそれを実行することです。

于 2012-05-08T09:55:14.910 に答える