Je cherche une solution rapide (comme dans une énorme performance, pas de solution rapide) pour persister et récupérer des dizaines de millions de petits objets binaires (environ 1k). Chaque objet doit avoir un identifiant unique pour la récupération (de préférence, un GUID ou SHA). Des exigences supplémentaires sont que cela devrait être utilisable de .NET et il ne doit pas nécessiter une installation supplémentaire du logiciel. p>
Actuellement, j'utilise une base de données SQLITE avec une seule table pour ce travail, mais je souhaite vous débarrasser de la surcharge du traitement des instructions SQL simples, telles que Sélectionner des données de Store où ID = ID. P>
J'ai également testé la persistance directe du système de fichiers sous NTFS, mais la performance se dégrade très vite dès qu'il atteint une demi-million d'objets. P>
P.s. Au fait, les objets n'ont jamais besoin d'être supprimés et le taux d'insertion est très très faible. En fait, chaque fois qu'un objet change une nouvelle version est stocké et la version précédente reste. C'est en fait une obligation de soutenir les déplacements du temps. P>
Il suffit d'ajouter des informations supplémentaires à ce fil: p>
à blob ou non à blob: stockage d'objets volumineux dans une base de données ou un système de fichiers http: / /arxiv.org/abs/cs.db/0701168 P>
10 Réponses :
Je pense que la requête de la base de données est votre meilleure mise. p>
L'ensemble de la structure d'une base de données est à l'écoute de ce type de cas, et l'analyse et l'optimisation de la requête simple est insignifiante tout à fait insignifiante. P>
Vous pourriez peut-être utiliser un schéma dans lequel vous stockez tous les objets d'une grosse blob directement au système de fichiers, puis ouvrez une vue de fichier mappée de mémoire dessus et indexez les identifiants d'objet avec un décalage dans le blob, Mais je doute que vous verriez beaucoup plus de perf au des dB, car c'est essentiellement ce que cela fait. P>
Je ne suis pas si sûr. S'il s'agit simplement d'une question de recherche et de récupération simples, l'utilisation du système de fichiers peut avoir plus de sens, tant qu'aucun répertoire ait trop de fichiers à l'intérieur.
Stocker un index distinct (un autre fichier) de [GUID -> Numéro de fichier + Décalage dans le fichier]. Utilisez une recherche binaire de récupération et passez à fichier n + 1 chaque fois que le fichier n atteint une certaine taille. Chaque ligne du fichier d'index n'est que de 24 octets (taille fixe: GUID + numéro de fichier + décalage, fichiers fractionnés à 4 Go) et le tri rapide (l'insertion Trier à un faible taux.) P>
Edit: Vous avez des exigences très simples qui sont simples à optimiser. Ce système soigneusement construit devrait surperformer la base de données, en particulier si vous faites attention à des lectures de blocs des données et de l'IO asynchrone. Les requêtes de la base de données auront toujours les frais généraux de l'analyse. P>
Edit 2: Si vous en avez besoin de sécurité (toujours une bonne idée), jetez un coup d'œil ici pour une description de la manière dont le concept de Les transactions système de fichiers peuvent vous aider à résister à la balle. p>
Accéder directement à de grands fichiers de cette façon sembler de supplier des problèmes de cohérence lors de la mise hors tension et des trucs. Je voudrais vraiment compenser ce genre de problèmes à la structure sous-jacente. Bonne idée, néanmoins.
Jetez un coup d'œil aux transactions système de fichiers (mon édition). L'API lié est nouvelle à Vista, mais les concepts peuvent être mis en œuvre dans le code pour XP si vous aviez besoin.
Vous pourrez peut-être réduire les problèmes de performance de NTFS en rompant l'identifiant de l'objet de l'objet en morceaux et en les utilisant en tant que noms d'annuaire. De cette façon, chaque répertoire contient uniquement un nombre limité de sous-répertoires ou de fichiers. P>
E.g. Si l'identifiant est AAAA-BB-CC-DDDDEEEEE CODE>, le chemin d'accès à l'élément serait
c: \ store \ aaaa \ bbcc \ dddd \ eeee.dat code>, limitant chaque annuaire à pas plus de 64k subitems. p>
Très semblable à la façon dont git stocke des morceaux, non? Je vais faire des tests de performance avec ce schéma.
J'ai fait quelque chose comme celui-ci avec des données de fonds communs de placement. Ça marche bien. L'astuce est de trouver le bon équilibre. Cela dépend de vos données particulières. Vous pourriez également être capable de faire du hasard si vous avez trop de zones clommées. Voir ma réponse pour plus de détails.
NTFS est une véritable performance de chien sage, vous pouvez vous éloigner de la Linux, mais pas de NTFS.
@Jottos - Quand vous dites "sortir avec ceci", voulez-vous dire que les flics ou le gang de Scooby Doo vont se présenter à la maison de l'opération s'ils essaient ma suggestion sur Windows? Le point entier est que NTFS ralentit lorsqu'il existe de nombreux fichiers dans un répertoire. En divisant les fichiers en une hiérarchie plus profonde, cela est évité et une meilleure performance est maintenue. Cela fonctionne comme une table de hachage à plusieurs niveaux.
Tableau de hachage multi-niveaux! Jamais de cela ... Je ne pense pas que la recherche de GUID est celle-ci, mais peut-être que je pourrais peut-être modifier un peu plus loin en divisant le GUID en 4 colonnes INT32 (ou 2 colonnes INT64). Va essayer ...
Ma mise en œuvre était sur Windows et Linux. C'est pourquoi j'ai rompu les fichiers. Travaillé bien sur les deux.
Vous voudrez certainement rompre les choses dans les sous-résidents en quelque sorte. Mais, je ne sais pas si cela la meilleure idée de beaucoup de fichiers minuscules. Votre goulot d'étranglement sera sur le disque IO, surtout si vous accédez à des fichiers aléatoires sur le disque. Vous êtes à la merci du cache du système d'exploitation du système d'exploitation pour stocker des fichiers en mémoire. Avec une base de données, vous pouvez avoir un peu plus de contrôle sur ce qui reste en mémoire. Au moins, vous pouvez faire la mémoire DB ~ = la mémoire système. Aussi, avec des objets DB et 1KB, vous pouvez noter avoir besoin de blobs; La plupart des DBS supportent de très grandes varcharars. Je vrais peut-être la peine d'analyser les varcharars vs blobs.
Vous avez besoin d'appeler un Préparer la fonction uniquement une fois par déclaration, avec paramètre indiqué par exemple. par ? code> (donc
Sélectionnez les données de stocker où id =? code> est la déclaration que vous prépareriez); Ensuite, qu'est-ce que vous faites "des millions de fois" est juste pour lier le paramètre dans la préparation Déclaration et appel
SQLITE_STEP CODE> - Ce sont des opérations rapides. Mérite de benchmarking si blob ouvert pourrait ne pas être encore plus rapide. Je recommande de coller avec SQLite et de creuser dans son interface de bas niveau (de géré C ++ si vous devez) pour une performance maximale - c'est vraiment un petit moteur incroyable, et cela m'a souvent surpris favorablement avec ses performances! P>
Je prépare déjà mes déclarations, même si je n'ai jamais essayé Blob ouvert. Besoin d'évaluer ses performances. Thnks.
Avez-vous envisagé d'essayer une base de données d'objet, comme DB4O ? Il peut persister n'importe quel CLR Objekt et les accéder rapidement à la langue de requête (supporte Linq!). Je n'avais pas de millions d'objets, mais avec quelques milliers d'accès était assez rapide, pas de différence majeure que la requête SQL similaire avec le champ ID indexé. p>
Cela semble intéressant. Je pense que je vais faire des tests de performance avec elle.
Hugo, comment ces tests de performance sont-ils allés?
Que diriez-vous d'un fichier binaire avec des blocs de taille fixe d'environ 2K, que les 4 premiers octets soient la longueur de l'objet ... P>
Emplacement de l'objet I est sur i * 2048 octets, puis lisez 2048 octets pour l'objet, en obtenant la longueur de l'objet réel des 4 premiers octets (non signés). P>
Bien que l'objet moyen soit très petit, rien n'interdit qu'il soit supérieur à 2K. Je pense que le plus gros objet que j'ai est d'environ 30k dans cette instanciation particulièrement de l'entrepôt. S'appuyant sur des morceaux de taille fixe nécessiterait probablement de partitionnement de gros objets et de traiter des problèmes de cohérence. Belle suggestion, mais je préférerais préférer que les problèmes liés à l'infrastructure sous-jacente.
J'aime la solution de Earwicker. La façon dont j'ai traitée cela est très similaire. P>
Qu'est-ce que j'ai fait était ceci: p>
Disons que votre GUID est 3F2504E0-4F89-11D3-9A0C-0305E82C3301. P>
hachage le GUID jusqu'à une hachage de trois lettres. AAA-ZZZ. P>
Supposons, pour des raisons d'argumentation, que votre guid est atteint "xap". p>
Vos informations seront trouvées dans le fichier C: \ Store \ x \ xa \ xap \ 3f2504e04f8911d39a0c0305e82c3301.dat p>
Naturellement, il existe de nombreuses variantes de cette stratégie. Par exemple, XAP pourrait être un fichier avec tous les objets binaires ajoutés ensemble, avec un en-tête ou un fichier externe contenant les GUID et compenser dans le fichier. P>
Vous pouvez vérifier si Les structures HDF5 conviennent à vos tâches p>
Jamais entendu parler. Va vérifier. Merci.
Vous êtes les bienvenus :) J'essaye avec HDF5 via Pytables de Python dans mon projet actuel et essayera peut-être de les utiliser comme une structure de données intermédiaire entre les scripts et l'analyse de Python "ETL" avec R. Si vous partagez vos résultats de test, ce sera génial :)
Oui, je vais certainement publier des résultats comparatifs dès que je mettez ces différentes stratégies.
J'ai tendance à convenir avec Alex, si vous écrivez votre propre solution, vous réinventez des trucs déjà probables dans SQLite, mais si vous devez ... P>
Vous pouvez probablement faire un travail BTREE ici. C'est le chômage de n'importe quelle base de données et votre espace problématique n'est pas tout ce mal. Les 10 millions d'objets de 1k ne représentent toujours que 10 de milliards d'octets, de sorte que le fichier est gérable par le système d'exploitation et il y a beaucoup d'exemples BTRee à essayer. P>
comparé à l'utilisation de la structure de répertoire système de fichiers pour créer essentiellement un analogue BTREE à l'aide d'un vrai Bree va être beaucoup plus rapide. P>
Une autre solution qui pourrait être intéressante est Mogilfs qui est un système de fichiers redondant distribué. < / p>
Je ne sais pas si SQLite Support Index ou non, mais si tel est le cas, vous pouvez accélérer les choses en créant un index sur le champ ID. P>
Si ce n'est pas le cas, votre meilleure option est B + arbres. Merci p>
Il semble que mes tests préliminaires (In Nunit) suggèrent un vecteur de temps de lecture de lecture cumulatif [10, 100, 1000] d'objets de 0,3 secondes de SQLite et de 3,01 à l'aide de NTFS, pour un objet de 50 MY. :-(
Mais lire 10k objets en 2.8S est toujours trop lent pour moi :-(
J'aurais besoin de quelque chose comme 100k en environ 1s.
Que diriez-vous d'une recherche intermédiaire comme Redis? Voir code.google.com/p/redis
Je pense que MySQL va simplement «manger» cela même sur NTFS. Utilisez des blobs. Normaliser à 3NF .. Que vous pour vous dire, NTFS et Windows XP n'ont pas été faits pour un grand accès concurrent aux fichiers. Ceci est un système d'exploitation utilisateur et est adapté à cette performance. Voyez si vous pouvez avoir un serveur de base de données sur Linux ...