2010-03-26 10 views
9

Je travaille avec une base de données mysql assez grande (plusieurs millions de lignes) avec une colonne stockant des images BLOB. L'application tente de saisir un sous-ensemble des images et exécute certains algorithmes de traitement sur eux. Le problème que je rencontre est que, en raison de l'assez grand ensemble de données que j'ai, l'ensemble de données que ma requête retourne est trop grand pour stocker en mémoire.Faire face à un grand nombre de résultats SQL

Pour le moment, j'ai changé la requête pour ne pas retourner les images. Pendant l'itération sur le jeu de résultats, j'exécute une autre sélection qui saisit l'image individuelle qui se rapporte à l'enregistrement en cours. Cela fonctionne, mais les dizaines de milliers de requêtes supplémentaires ont entraîné une diminution des performances inacceptable.

Mon idée suivante consiste à limiter la requête d'origine à 10 000 résultats environ, puis de poursuivre l'interrogation sur des intervalles de 10 000 lignes. Cela semble être le compromis entre les deux approches. Je pense qu'il y a probablement une meilleure solution que je ne connais pas. Existe-t-il une autre façon d'avoir seulement des parties d'un ensemble de résultats gigantesque en mémoire à la fois?

Cheers,

Dave McClelland

+0

Peut-être que mes problèmes de mémoire ne sont pas causés par la requête. Je suis revenu à une ancienne version (merci, contrôle de version), et le lecteur de données semble charger seulement la ligne qu'il lit actuellement, comme mentionné par Anthony. Cependant, je me demande s'il ne serait pas plus logique de garder les images sur le système de fichiers local au lieu de les transférer sur le réseau depuis le serveur de base de données (comme mentionné par ProphetBeal ci-dessous). L'inconvénient est qu'il serait stocké dans les deux emplacements (ils doivent rester dans la base de données pour l'utilisation d'autres systèmes), mais l'espace de stockage du système de fichiers n'est pas une préoccupation immédiate. Des commentaires à ce sujet? –

+0

Je donne la réponse à Anthony parce qu'il a souligné que le DataReader n'est pas la raison pour laquelle ma mémoire se remplissait (c'était quelque chose de différent, mais légèrement différent). Je vais probablement utiliser la solution de ProphetBeal de garder les BLOBs sur la machine locale pour éliminer la congestion du réseau, mais pour toute personne traitant avec un ensemble de données à stocker sur la machine locale, un DataReader devrait être une solution efficace. –

Répondre

3

Une option consiste à utiliser un DataReader. Il diffuse les données, mais au prix d'une connexion ouverte à la base de données. Si vous parcourez plusieurs millions de lignes et effectuez un traitement pour chacune d'entre elles, cela peut ne pas être souhaitable.

Je pense que vous êtes sur la bonne voie pour saisir les données en morceaux, probablement en utilisant la méthode Limit de MySql, n'est-ce pas?

+0

Oui, j'avais prévu d'utiliser la limite de SQL. –

+0

En outre, j'utilise déjà un DataReader pour stocker les résultats (en utilisant OdbcCommand.ExecuteReader() puis en itérant avec while (datareader.Read()). Il semble ne pas diffuser très efficacement car il remplissait toujours toute la mémoire système disponible –

+0

@Dave, quelqu'un d'autre peut être capable de donner un aperçu de l'utilisation spécifique de la mémoire du lecteur de données, mais je crois comprendre qu'il ne devrait avoir qu'un seul enregistrement en mémoire En tout cas, il devrait nécessiter beaucoup moins de ressources de mémoire qu'un DataSet ou un DataTable Vos problèmes de mémoire peuvent être le résultat de ce que vous faites avec les données une fois que vous les avez récupérées, combien de temps vous êtes garder ces objets dans la portée, etc. –

1

Lorsque vous traitez avec ces grands ensembles de données, il est important de ne pas avoir besoin de tout avoir en mémoire à la fois. Si vous écrivez le résultat sur disque ou sur une page Web, faites-le en lisant chaque ligne. N'attendez pas d'avoir lu toutes les lignes avant de commencer à écrire.

Vous pouvez également définir les images sur DelayLoad = true afin qu'elles ne soient récupérées que lorsque vous en avez besoin plutôt que d'implémenter cette fonctionnalité vous-même. Voir here pour plus d'informations.

+0

J'aurais dû le mentionner, je suis (actuellement) en train d'utiliser ADO.NET. Existe-t-il un équivalent de DelayLoad? Je pourrais migrer vers Linq, mais je préférerais ne pas le faire. Je vais mettre à jour les tags de question. En outre, je n'écris pas les résultats n'importe où. Je cours quelques algorithmes d'analyse d'image sur les résultats pour la comparer à une image passée dans la fonction. En conséquence, j'ai seulement besoin de stocker la meilleure image et peut ignorer le reste. Merci pour la réponse rapide! –

0

Je vois 2 options. 1) S'il s'agit d'une application Windows (par opposition à une application Web), vous pouvez lire chaque image à l'aide d'un lecteur de données et vider le fichier dans un dossier temporaire sur le disque, puis effectuer le traitement nécessaire contre le fichier physique.

2) Lire et traiter les données en petits morceaux. 10k lignes peuvent encore être beaucoup en fonction de la taille des images et du nombre de processus que vous voulez faire. Renvoyer 5 Ko de lignes à la fois et en lire plus dans un fil séparé quand il ne reste plus que 1 Ko à traiter peut permettre un processus transparent.

Même si ce n'est pas toujours recommandé, forcer la récupération de place avant de traiter le jeu de lignes suivant peut aider à libérer de la mémoire.

0

Je l'ai utilisé une solution comme celle qui est décrite dans ce tutoriel avant: http://www.asp.net/(S(pdfrohu0ajmwt445fanvj2r3))/learn/data-access/tutorial-25-cs.aspx

Vous pouvez utiliser le multi-threading pour pré-tirer une partie des quelques jeux de données (dans un premier temps tirer 1-10,000 et l'arrière-plan tire 10 001 - 20 000 et 20 001 - 30 000 lignes et supprime les pages précédentes des données (par exemple, si vous êtes entre 50 000 et 60 000, supprimez les 1 à 10 000 premières lignes pour conserver la mémoire si cela pose problème). l'emplacement de la "page" actuelle en tant que pointeur pour extraire la prochaine plage de données ou supprimer certaines données hors plage.

Questions connexes