Fondamentalement, j'utilise Entity Framework pour interroger une énorme base de données. Je souhaite renvoyer une liste de chaînes, puis la consigner dans un fichier texte.
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);
}
Cependant, j'ai eu une exception lorsque logFilePathFileName.Count=397000
. L'exception est:
Une exception de type 'System.OutOfMemoryException' a été levée.
Une exception de première chance du type 'System.OutOfMemoryException' S'est produite dans System.Data.Entity.dll
METTRE À JOUR:
Ce que je veux utiliser une requête différente, dites: sélectionnez 1000 premiers puis ajoutez à la liste, mais je ne sais pas après 1000 alors quoi?
Le plus probablement, il ne s'agit pas d'une RAM
en l'état, donc augmenter votre RAM
ou même compiler et exécuter votre code dans la machine 64
bit n'aura pas d'effet positif dans ce cas.
Je pense que cela est lié au fait que les collections de .NET
sont limitées à un maximum de 2GB
RAM espace (aucune différence ni 32
ni 64
bit).
Pour résoudre ce problème, scindez votre liste en morceaux beaucoup plus petits et probablement votre problème aura disparu.
Juste une solution possible:
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 !|
}
}
MODIFIER
Si vous voulez fragmenter une query , vous pouvez utiliser Skip(...)
et Take(...)
Juste un exemple explicatif:
var fisrt1000 = query.Skip(0).Take(1000);
var second1000 = query.Skip(1000).Take(1000);
...etc..
Naturellement, mettez-le dans votre itération et paramétrez-le sur la base de données que vous connaissez ou dont vous avez besoin.
Pourquoi collectez-vous les données dans un List<string>
si tout ce que vous avez à faire est de les écrire dans un fichier texte?
Vous pourriez aussi bien juste:
Vous aurez besoin de beaucoup moins de mémoire que maintenant, car vous ne garderez pas toutes ces chaînes inutilement en mémoire.
Vous aurez probablement besoin de définir quelques vmargs pour la mémoire!
Ce que dit Roy Dictus semble la meilleure solution. Vous pouvez également essayer d’ajouter une limite à votre requête. Donc, le résultat de votre base de données ne sera pas si grand.
Pour plus d'informations sur: Limitation de la taille de la requête avec un framework d'entités
Vous ne devriez pas lire tous les enregistrements de la base de données à la liste. Cela demandait beaucoup de mémoire. Vous pouvez combiner des enregistrements de lecture et les écrire dans un fichier. Par exemple, lisez 1000 enregistrements de la base de données dans une liste et enregistrez-les (ajoutez-les) dans un fichier texte, effacez la mémoire utilisée (list.Clear ()) et continuez avec les nouveaux enregistrements.
J'avais l'habitude d'utiliser l'arraylist gc dans VS c ++, semblable à la liste gc que vous avez utilisée, pour travailler avec des ensembles de données petits et intermédiaires, mais lors de l'utilisation de Big Dat, le même problème, 'System.OutOfMemoryException', était lancé. Comme la taille de ces gcs ne peut excéder 2 Go et que, par conséquent, le Big Data devient inefficace, j'ai construit ma propre liste chaînée, qui offre les mêmes fonctionnalités, une augmentation dynamique et un index obtenu. En gros, il s'agit d'une classe de liste chaînée normale, avec tableau dynamique à l'intérieur pour fournir des données par index, il duplique l'espace, mais vous pouvez supprimer la liste liée après la mise à jour du tableau si vous n'en avez pas besoin en conservant uniquement le tableau dynamique, cela résoudrait le problème. voir le code:
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++;
}
}
Si vous l'utilisez, référez-vous à mon travail https://www.liebertpub.com/doi/10.1089/big.2018.0064
J'ai lu dans plusieurs autres rubriques de StackOverflow qu'Entity Framework n'est pas conçu pour gérer des données en vrac de cette manière. L'EF mettra en cache/suivra toutes les données dans le contexte et provoquera une exception dans les cas de gros volumes de données. Les options consistent à utiliser directement le code SQL ou à fractionner vos enregistrements en ensembles plus petits.