9

基本上我使用实体框架来查询一个巨大的数据库。我想返回一个字符串列表,然后将其记录到一个文本文件中。

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.Data.Entity.dll 中出现“System.OutOfMemoryException”类型的第一次机会异常

更新:

我想使用不同的查询说:选择前 1000 名然后添加到列表中,但我不知道 1000 之后然后呢?

4

7 回答 7

16

很可能它不是按RAM原样进行的,因此在这种情况下,增加您RAM甚至64在位机中编译和运行您的代码不会产生积极影响。

.NET我认为这与集合仅限于最大2GBRAM 空间(没有区别3264位)的事实有关。

要解决此问题,请将您的列表拆分为更小的块,您的问题可能会消失。

只有一种可能的解决方案:

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(...)andTake(...)

只是一个解释性的例子:

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

Roy Dictus 所说的听起来是最好的方式。您也可以尝试为您的查询添加限制。所以你的数据库结果不会那么大。

有关信息: 使用实体框架限制查询大小

于 2013-01-30T14:19:37.167 回答
0

您不应该将数据库中的所有记录都读取到列表中。它需要大量的内存。你结合阅读记录并将它们写入文件。例如从 db 读取 1000 条记录到列表并将它们保存(附加)到文本文件,清除使用的内存(list.Clear())并继续新记录。

于 2013-01-30T14:17:24.897 回答
0

从 StackOverflow 上的其他几个主题中,我了解到实体框架并非旨在处理这样的批量数据。EF 将缓存/跟踪上下文中的所有数据,并在大量数据的情况下导致异常。选项是直接使用 SQL 或将记录拆分为较小的集合。

于 2013-01-30T14:19:22.277 回答
0

我曾经在 VS c++ 中使用与您使用的 gc List 类似的 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 回答