9

基本的に、Entity Framework を使用して巨大なデータベースにクエリを実行します。文字列リストを返し、それをテキスト ファイルに記録したいと考えています。

List<string> logFilePathFileName = new List<string>();
var query = from c in DBContext.MyTable where condition = something select c;
foreach (var result in query)
{
    filePath = result.FilePath;
    fileName = result.FileName;
    string temp = filePath + "." + fileName;
    logFilePathFileName.Add(temp);
    if(logFilePathFileName.Count %1000 ==0)
        Console.WriteLine(temp+"."+logFilePathFileName.Count);
}

ただし、例外が発生しましたlogFilePathFileName.Count=397000。例外は次のとおりです。

タイプ 'System.OutOfMemoryException' の例外がスローされました。

タイプ 'System.OutOfMemoryException' の初回例外が System.Data.Entity.dll で発生しました

アップデート:

別のクエリを使用して言いたいこと: トップ 1000 を選択してからリストに追加しますが、1000 以降はわかりません。

4

7 に答える 7

16

ほとんどの場合、それはそのままでRAMはありません。この場合、コードを増やしたりRAM、ビットマシンでコードをコンパイルして実行したりしても64、プラスの効果はありません。

.NETコレクションが最大2GBRAMスペースに制限されているという事実に関連していると思います(違い3264ビットもありません)。

これを解決するには、リストをより小さなチャンクに分割すると、おそらく問題は解決します。

考えられる解決策は1つだけです:

foreach (var result in query)
{
    ....
    if(logFilePathFileName.Count %1000 ==0) {
        Console.WriteLine(temp+"."+logFilePathFileName.Count);
        //WRITE SOMEWHERE YOU NEED 
        logFilePathFileName = new List<string>(); //RESET LIST !|
    }
}

編集

クエリをフラグメント化する場合はSkip(...)、およびを使用できますTake(...)

単なる説明例:

var fisrt1000 = query.Skip(0).Take(1000);
var second1000 = query.Skip(1000).Take(1000);

... 等々..

自然にそれを繰り返しに入れ、既知または必要なデータの境界に基づいてパラメータ化します。

于 2013-01-30T14:16:05.113 に答える
3

データをテキスト ファイルに書き込むだけでよいのに、なぜデータを収集するのList<string>でしょうか。

次のようにすることもできます。

  • テキスト ファイルを開きます。
  • レコードを反復処理し、各文字列をテキスト ファイルに追加します (文字列をメモリに格納することはありません)。
  • テキスト ファイルをフラッシュして閉じます。

これらすべての文字列を不必要にメモリに保持する必要がないため、現在よりもはるかに少ないメモリで済みます。

于 2013-01-30T14:15:54.040 に答える
1

おそらくメモリ用にいくつかのvmargsを設定する必要があります!また...リストに保持せずにファイルに直接書き込むことを検討してください

于 2013-01-30T14:17:43.327 に答える
1

ロイ・ディクタスの言うことは最高の方法に聞こえます。また、クエリに制限を追加することもできます。したがって、データベースの結果はそれほど大きくなりません。

詳細: エンティティ フレームワークを使用したクエリ サイズの制限

于 2013-01-30T14:19:37.167 に答える
0

データベースからリストまですべてのレコードを読み取るべきではありません。大量のメモリが必要でした。レコードの読み取りとファイルへの書き込みを組み合わせます。たとえば、dbから1000レコードを読み取ってリストし、それらをテキストファイルに保存(追加)し、使用済みメモリをクリアして(list.Clear())、新しいレコードを続行します。

于 2013-01-30T14:17:24.897 に答える
0

StackOverflow に関する他のいくつかのトピックから、Entity Framework はそのような大量のデータを処理するように設計されていないことを読みました。EF はコンテキスト内のすべてのデータをキャッシュ/追跡し、膨大な量のデータの場合に例外を引き起こします。オプションは、SQL を直接使用するか、レコードを小さなセットに分割することです。

于 2013-01-30T14:19:22.277 に答える
0

以前は、使用した gc List と同様に VS c++ で gc arraylist を使用して、小規模および中間のデータ セットで正常に動作しましたが、Big Dat を使用すると、同じ問題 'System.OutOfMemoryException' がスローされました。これらの gcs のサイズは 2 GB を超えることができないため、ビッグ データでは非効率になるため、同じ機能、動的増加、およびインデックスによる取得を提供する独自のリンク リストを作成しました。基本的に、これは通常のリンク リスト クラスであり、内部に動的配列を使用してインデックスでデータを取得すると、スペースが複製されますが、動的配列のみを保持する必要がない場合は、配列を更新した後にリンクされたリストを削除できます。これにより、問題が解決します。コードを参照してください:

struct LinkedNode
{
    long data;
    LinkedNode* next;
};


class LinkedList
{
public:
    LinkedList();
    ~LinkedList();
    LinkedNode* head;
    long Count;
    long * Data;
    void add(long data);
    void update();
    //long get(long index);
};

LinkedList::LinkedList(){
    this->Count = 0;
    this->head = NULL;
}

LinkedList::~LinkedList(){
    LinkedNode * temp; 
    while(head){
        temp= this->head ;
        head = head->next;
        delete temp;
    }
    if (Data)
        delete [] Data; Data=NULL;
}

void LinkedList::add  (long data){
    LinkedNode * node = new LinkedNode();
    node->data = data;
    node->next = this->head;
    this->head = node;
    this->Count++;}

void LinkedList::update(){
    this->Data= new long[this->Count];
    long i = 0;
    LinkedNode * node =this->head;
    while(node){
        this->Data[i]=node->data;
        node = node->next;
        i++;
    }
}

これを使用する場合は、私の作品を参照してください https://www.liebertpub.com/doi/10.1089/big.2018.0064

于 2018-09-29T13:13:19.017 に答える