Je crée actuellement une application Web qui permet aux utilisateurs de stocker et de partager des fichiers, de 1 Mo à 10 Mo.
Il me semble que le stockage des fichiers dans une base de données ralentira considérablement l'accès à la base de données.
Est-ce une préoccupation valable? Est-il préférable de stocker les fichiers dans le système de fichiers et d'enregistrer le nom et le chemin d'accès au fichier dans la base de données? Existe-t-il des meilleures pratiques concernant le stockage de fichiers lors de l'utilisation d'une base de données?
Je travaille dans PHP et MySQL pour ce projet, mais le problème est le même pour la plupart des environnements ( Ruby on Rails , PHP , . NET ) et les bases de données (MySQL, PostgreSQL ).
Raisons en faveur du stockage des fichiers dans la base de données:
Raison contre le stockage de fichiers dans la base de données:
FILESTREAM
de SQL Server et devez migrer vers un autre système de base de données.OMI, jugeant le stockage des fichiers dans la base de données ou non comme "mauvais" nécessite plus d'informations sur les circonstances et les exigences. La taille et/ou le nombre de fichiers seront-ils toujours petits? N'est-il pas prévu d'utiliser le stockage cloud? Les fichiers seront-ils servis sur un site Web ou un exécutable binaire comme une application Windows?
En général, mon expérience a montré que le stockage des chemins est moins coûteux pour l'entreprise, même en tenant compte du manque d'ACID et de la possibilité d'orphelins. Cependant, cela ne signifie pas qu'Internet n'est pas légion avec des histoires de manque de contrôle ACID qui vont mal avec le stockage de fichiers, mais cela signifie qu'en général, cette solution est plus facile à construire, à comprendre et à maintenir.
Dans de nombreux cas, c'est une mauvaise idée. Cela gonflera les fichiers de la base de données et provoquera plusieurs problèmes de performances. Si vous collez les blobs dans un tableau avec un grand nombre de colonnes, c'est encore pire.
Toutefois! Certaines bases de données, comme SQL Server ont un type de colonne FILESTREAM. Dans ce cas, vos données sont réellement stockées dans un fichier séparé sur le serveur de base de données et seul un ID du fichier est enregistré dans la table. Dans ce cas, je ne vois pas beaucoup de raisons de ne pas conserver les données sur le serveur SQL. Les fichiers sont automatiquement inclus dans le cadre de la sauvegarde du serveur, et la base de données et les fichiers ne sont jamais désynchronisés. Le problème avec la suggestion de Tony de stocker les noms de fichiers, c'est que la base de données et le système de fichiers peuvent se désynchroniser. La base de données prétendra qu'un fichier existe lorsqu'il a été supprimé sur le disque. Si un processus modifie la base de données puis se bloque, les fichiers et la base de données ne correspondront pas (c.-à-d. Pas ACIDE avec des fichiers en dehors d'une base de données).
Oui, c'est une mauvaise pratique.
Impact sur les performances de la base de données:
SELECT
avec n'importe quelle colonne BLOB, vous effectuerez toujours un accès au disque, tandis que sans BLOB vous aurez une chance d'obtenir des données directement de RAM (la base de données à haut débit sera optimisée pour tenir les tables dans la RAM);Avantage de vitesse - aucun ! Bien que certains systèmes de fichiers plus anciens ne gèrent pas bien les répertoires contenant des millions de fichiers, la plupart des systèmes modernes n'ont aucun problème du tout et utilisent en fait le même type de structures de données que les BD (généralement des arbres B). Par exemple, ext4 (système de fichiers Linux par défaut) utilise Htree .
Conclusion: cela gênera les performances de votre base de données et n'améliorera pas les performances de récupération des fichiers.
De plus, puisque vous parlez d'application Web - servir des fichiers statiques directement à partir d'un système de fichiers en utilisant un serveur Web moderne, ce qui peut faire sendfile()
syscall est énorme amélioration des performances. Ce n'est bien sûr pas possible si vous récupérez des fichiers à partir de DB. Considérons par exemple cette référence , montrant Ngnix effectuant 25 000 requêtes/s avec 1000 connexions simultanées sur un ordinateur portable bas de gamme. Ce type de charge ferait frire n'importe quel type de DB.
Je serais pragmatique à ce sujet et je suivrais le principe "ne pas encore optimiser". Faites la solution qui a du sens pour le moment, et celle que vous avez les ressources de développement pour mettre en œuvre correctement. Il y a beaucoup de problèmes potentiels. Mais ceux-ci ne deviennent pas nécessairement de vrais problèmes. Par exemple. Ce ne serait probablement pas un problème si vous avez 100 utilisateurs. Cela pourrait être un problème si vous avez 100 000 ou 10 000 000 d'utilisateurs. Mais dans ce dernier cas, il devrait y avoir une base pour plus de ressources de développement pour traiter tous les problèmes.
Mais le stockage des données dans la base de données vous évite de traiter d'autres problèmes, par exemple où les fichiers doivent-ils être stockés, comment doivent-ils être sauvegardés, etc. Puisque vous écrivez une application Web, ce serait une très bonne idée pour des raisons de sécurité de s'assurer que le processus hébergeant l'application n'a pas accès en écriture au fichier. système, vous devez donc configurer le serveur afin que le processus ait un accès en lecture/écriture au dossier où les données sont stockées.
Je choisirais personnellement de stocker les données dans la base de données, mais assurez-vous que les BLOBS ne sont pas lus jusqu'à ce qu'ils soient vraiment nécessaires, c'est-à-dire qu'aucun "SELECT * FROM ..." ne soit exécuté sur ces tables contenant des blogs. Et je m'assurerais que la conception facilite le déplacement des données de la base de données vers le système de fichiers si vous rencontrez des problèmes de performances. Par exemple, stockez les informations du fichier dans une table séparée Fichier , gardant ainsi les informations du fichier à l'écart des autres entités commerciales.
En supposant que vous ayez une classe File pour représenter un fichier lu dans la base de données, l'impact du codage de son déplacement ultérieur sera minime.
Microsoft a publié un livre blanc à ce sujet il y a quelques années. Il se concentre sur SqlServer, mais vous pouvez y trouver des informations intéressantes:
Une version très concise de leur conclusion est:
Lorsque vous comparez le système de fichiers NTFS et SQL Server 2005, les BLOBS inférieurs à 256 Ko sont gérés plus efficacement par SQL Server, tandis que NTFS est plus efficace pour les BLOBS supérieurs à 1 Mo.
Je vous recommande d'écrire quelques petits tests pour votre cas d'utilisation particulier. Gardez à l'esprit que vous devez vous méfier des effets de mise en cache. (J'ai été étonné la première fois que j'ai obtenu des vitesses de sauvegarde sur disque qui semblaient avoir des débits plus élevés que ce qui était physiquement possible!)
La vieille sagesse conventionnelle de stocker des fichiers en dehors de la base de données pourrait ne plus être valable. Par principe, je préférerais l'intégrité à la vitesse, et avec un SGBD moderne, vous pouvez avoir les deux.
Tom Kyte semble d'accord :
Je ne connais aucun avantage à stocker des données que je souhaite conserver longtemps en dehors d'une base de données.
S'il est dans la base de données, je peux
assurez-vous qu'il est géré de manière professionnelle
sauvegardé
récupérable (avec le reste des données)
sécurisé
évolutif (essayez de mettre 100 000 documents dans un seul répertoire, maintenant, mettez-les dans le tableau - lequel "évolue" - ce n'est pas le répertoire)
Je peux récupérer (flashback) facilement
J'ai le verrouillage
J'ai lu la cohérence ...
Oui.
Si vous servez un fichier de votre système de fichiers, votre serveur Web peut utiliser le code du noyau comme sendfile () sur BSD ou Linux pour copier le fichier directement dans le socket. C'est très rapide et très efficace.
Servir des fichiers hors de la base de données signifie que vous devez copier les données du disque du serveur de base de données dans la mémoire du serveur de base de données, puis de la mémoire du serveur db vers le port réseau du serveur db, puis du réseau vers votre processus de serveur Web, puis de nouveau vers le connexion réseau sortante.
Sauf si vous avez une très bonne raison de ne pas le faire, il est toujours préférable de servir des fichiers statiques à partir du système de fichiers.
Le célèbre Tom Kyte a écrit qu'ils (l'Oracle) utilisent la base de données Oracle comme serveur de fichiers et que cela fonctionne parfaitement bien, encore plus rapidement qu'un système de fichiers normal, avec une transactionnalité complète, aucune perte de performances et une seule sauvegarde.
Oui, mais notez, ils sont le producteur de la base de données Oracle et pour tout autre utilisateur, il y a des problèmes de coût. L'utilisation de bases de données commerciales telles qu'Oracle pour le stockage de fichiers est tout simplement inefficace.
Cependant, avec PostgreSQL par exemple, vous pouvez simplement exécuter une autre instance de base de données uniquement pour le stockage d'objets blob. Vous disposez alors d'un support transactionnel complet. Mais la transactionnalité coûte de l'espace DB. Il est nécessaire que la base de données stocke plusieurs instances d'objets blob pour plusieurs transactions simultanées. Sur PostgreSQL, c'est le plus douloureux, car cette base de données stocke les doublons de blobs créés pour la transaction sont stockés même s'ils ne sont plus nécessaires, jusqu'à ce que le processus VACUUM soit terminé.
Avec le stockage du système de fichiers, en revanche, vous devez être très prudent lorsque quelqu'un modifie le fichier, car la transaction peut être annulée et la copie du fichier doit être conservée jusqu'à ce que l'ancienne version ne soit plus visible.
Dans le système où les fichiers sont uniquement ajoutés et supprimés et où l'accès transactionnel aux fichiers n'est pas un problème, le stockage du système de fichiers sera à mon humble avis le meilleur choix.
Il est généralement préférable de stocker les BLOB de grande taille dans une table distincte et de simplement conserver une référence de clé étrangère au BLOB dans votre table principale. De cette façon, vous pouvez toujours récupérer le fichier à partir de la base de données (vous n'avez donc pas besoin de code spécial) et vous évitez les problèmes liés aux dépendances de base de données externes (en maintenant la base de données et le système de fichiers synchronisés, etc.), mais vous n'encourez que cette surcharge si vous vous joignez explicitement à cette table (ou effectuez un appel distinct). 10 Mo ne sont pas terriblement volumineux, la plupart des bases de données commerciales modernes n'auront pas de problème. La seule raison pour laquelle je stockerais un fichier dans le système de fichiers est de réduire la bande passante de la base de données. Si votre base de données va mélanger un grand nombre de ces fichiers, vous devrez peut-être fractionner la charge de travail et ne stocker qu'un descripteur de fichier quelconque. Ensuite, vous pouvez avoir un appel distinct pour charger le fichier à partir d'un autre serveur, de sorte que vous n'attachez pas vos connexions à la base de données (et les connexions réseau sur votre serveur de base de données) avec tous ces transferts de fichiers.
Vous pourriez rencontrer certains de ces problèmes:
SELECT *
qui implique la ligne avec le gros blob prend très longtemps, même si vous n'avez pas besoin du blob (bien sûr, vous devez faire une sélection spécifique, mais parfois les applications sont écrites comme ceci)Bien sûr, vous bénéficiez également de certains avantages:
Personnellement je ne le fais pas car je trouve les inconvénients bien plus lourds que les pros. Mais comme indiqué ci-dessus, cela dépend totalement de votre cas d'utilisation et autres.
Certains systèmes de gestion de contenu d'entreprise, comme SiteCore, utilisent une base de données pour stocker les données de page et une autre base de données pour stocker les fichiers. Ils utilisent MS SQL Server.
Pour une mise en œuvre pratique, voici ce qui peut vous préoccuper:
Benifits:
Inconvénients:
C'est l'un de ces "Puis-je utiliser une lame de rasoir pour couper une pomme?" Oui, vous pouvez.
Devrais-tu? À qui le dire ...
Je suppose que lorsque vous vous trouvez dans la situation où votre outillage le permet ou est le seul outillage disponible (au moins pour obtenir ce délai). Par exemple, j'ai utilisé un tournevis plat pour retirer un type de boulon philips ... était-ce correct? était-ce le bon outil? C'était un mauvais choix?
La réponse à ce cas est: la base de données n'est pas censée stocker des fichiers ... chaque fois que vous le faites, c'est mal, de la même manière théoriquement, je n'aurais pas dû utiliser le tournevis plat pour retirer le boulon philips, car ce faisant, j'ai perdu l'avantage du tournevis Philips de ne pas se déplacer et d'endommager tout ce sur quoi je travaille (comme vous perdriez des avantages si vous utilisez une base de données comme solution de stockage de fichiers) ... pourtant j'ai correctement calculé le risque et tout s'est très bien passé.
si vous souhaitez bien faire les choses, vous devriez probablement utiliser git pour stocker vos fichiers et conserver les hachages git nécessaires dans votre base de données pour faire référence à la bonne version de fichier dont vous avez besoin ... de la même manière que j'ai pu accéder à mon outil boîte et obtenir le putain de tournevis philips ...