Stockage d'images dans PostgreSQL

111

Très bien, je travaille donc sur une application qui utilisera un back-end Linux exécutant PostgreSQL pour servir des images à une boîte Windows avec le front-end écrit en C # .NET, bien que le front-end ne devrait guère avoir d'importance. Ma question est:

  • Quelle est la meilleure façon de gérer le stockage des images dans Postgres?

Les images mesurent environ 4 à 6 mégapixels chacune, et nous en stockons plus de 3 000. Il peut également être bon de noter: ce n'est pas une application Web, il y aura au plus environ deux frontaux accédant à la base de données à la fois.

akdom
la source

Réponses:

64

Mise à jour en 2012, lorsque nous constatons que les tailles d'image et le nombre d'images augmentent et augmentent, dans toutes les applications ...

Nous avons besoin d'une certaine distinction entre «image originale» et «image traitée», comme la vignette.

Comme le dit la réponse de Jcoby, il y a deux options, alors je recommande:

  • utilisez blob (Binary Large OBject): pour le magasin d'images d'origine, à votre table. Voir la réponse d'Ivan (pas de problème avec la sauvegarde des blobs!), Les modules supplémentaires fournis par PostgreSQL , les procédures, etc.

  • utiliser une base de données séparée avec DBlink : pour le magasin d'images d'origine, dans une autre base de données (unifiée / spécialisée). Dans ce cas, je préfère bytea , mais blob est presque le même. La séparation de la base de données est le meilleur moyen pour un "service Web d'image unifiée".

  • use bytea (BYTE Array): pour la mise en cache des images miniatures. Mettez en cache les petites images pour les envoyer rapidement au navigateur Web (pour éviter les problèmes de rendu) et réduire le traitement du serveur. Mettez également en cache les métadonnées essentielles, comme la largeur et la hauteur. La mise en cache de la base de données est le moyen le plus simple, mais vérifiez vos besoins et les configurations de serveur (ex. Modules Apache): stocker les vignettes dans le système de fichiers peut être mieux, comparer les performances. N'oubliez pas qu'il s'agit d'un service Web (unifié), puis qu'il peut être stocké dans une base de données distincte (sans sauvegarde), desservant de nombreuses tables. Voir aussi le manuel des types de données binaires PostgreSQL , les tests avec la colonne bytea , etc.

NOTE1: aujourd'hui l'utilisation de «solutions doubles» (base de données + système de fichiers) est obsolète (!). Il y a de nombreux avantages à utiliser "uniquement la base de données" au lieu du double. PostgreSQL a des performances comparables et de bons outils pour l'exportation / importation / entrée / sortie.

NOTE2: rappelez-vous que PostgreSQL n'a que bytea , pas de BLOB d'Oracle par défaut : "Le standard SQL définit (...) BLOB. Le format d'entrée est différent de bytea, mais les fonctions et opérateurs fournis sont pour la plupart les mêmes", Manuel .


EDIT 2014 : Je n'ai pas changé le texte original ci-dessus aujourd'hui (ma réponse était le 22 avril 12, maintenant avec 14 votes), j'ouvre la réponse pour vos changements (voir "Mode Wiki", vous pouvez éditer!), Pour relecture et pour les mises à jour .
La question est stable (réponse de @ Ivans '08 avec 19 votes), aidez-nous à améliorer ce texte.

Peter Krauss
la source
2
Quelle est la référence pour "... l'utilisation de" solutions doubles "(base de données + système de fichiers) est déconseillée ..."?
dangel
Quelques nouveautés 2019! Depuis 2018, PostgREST prend en charge la sortie directe de bytea sur le Web. Voir cette configuration simple NGINX pour l'utiliser. Voir le guide PostgREST sur la sortie binaire
Peter Krauss
52

Re réponse de jcoby:

bytea étant une colonne "normale" signifie également que la valeur est lue complètement en mémoire lorsque vous la récupérez. Blobs, en revanche, vous pouvez diffuser dans stdout. Cela aide à réduire l'empreinte mémoire du serveur. Surtout lorsque vous stockez 4 à 6 images MPix.

Aucun problème avec la sauvegarde des blobs. pg_dump fournit l'option "-b" pour inclure les gros objets dans la sauvegarde.

Donc, je préfère utiliser pg_lo_ *, vous pouvez le deviner.

Re réponse de Kris Erickson:

Je dirais le contraire :). Lorsque les images ne sont pas les seules données que vous stockez, ne les stockez pas sur le système de fichiers sauf si vous devez absolument le faire. C'est un tel avantage d'être toujours sûr de la cohérence de vos données et d'avoir les données "en un seul morceau" (la base de données). BTW, PostgreSQL est excellent pour préserver la cohérence.

Cependant, il est vrai que la réalité est souvent trop exigeante en termes de performances ;-), et elle vous pousse à servir les fichiers binaires du système de fichiers. Mais même dans ce cas, j'ai tendance à utiliser la base de données comme stockage «maître» pour les binaires, avec toutes les autres relations liées de manière cohérente, tout en fournissant un mécanisme de mise en cache basé sur le système de fichiers pour l'optimisation des performances.

Ivan Krechetov
la source
15
Après 10 ans, pensez-vous que vos points sont toujours valables? Des mises à jour depuis?
leventunver
3
@leventunver Non, les points à ne pas tenir. Par exemple, le premier sur le fait d' BYTEAêtre une colonne «normale». Postgres prend en charge le streaming depuis / vers les BYTEAcolonnes depuis de nombreuses années, ce qui signifie que vous n'avez pas à stocker le contenu en mémoire avant de le stocker dans la base de données.
oligofren
29

Dans la base de données, il existe deux options:

  • bytea. Stocke les données dans une colonne, exportées dans le cadre d'une sauvegarde. Utilise les fonctions de base de données standard pour enregistrer et récupérer. Recommandé pour vos besoins.
  • blobs. Stocke les données en externe, pas normalement exportées dans le cadre d'une sauvegarde. Nécessite des fonctions de base de données spéciales pour enregistrer et récupérer.

J'ai utilisé des colonnes bytea avec beaucoup de succès dans le passé, stockant plus de 10 Go d'images avec des milliers de lignes. La fonctionnalité TOAST de PG annule à peu près tout avantage des blobs. Vous devrez inclure des colonnes de métadonnées dans les deux cas pour le nom de fichier, le type de contenu, les dimensions, etc.

jcoby
la source
1
10 Go, ce n'est pas beaucoup :-( Je cherche une solution TB
Valentin Heinitz
2
@ValentinHeinitz Pour les tuberculeux, Postgres vanille a du mal même avec des colonnes de texte plus petites.
sudo
23

Mise à jour rapide à la mi-2015:

Vous pouvez utiliser l' interface Postgres Foreign Data , pour stocker les fichiers dans une base de données plus appropriée. Par exemple, placez les fichiers dans un GridFS qui fait partie de MongoDB. Ensuite, utilisez https://github.com/EnterpriseDB/mongo_fdw pour y accéder dans Postgres.

Cela présente les avantages que vous pouvez y accéder / lire / écrire / sauvegarder dans Postrgres et MongoDB, en fonction de ce qui vous donne plus de flexibilité.

Il existe également des wrappers de données étrangers pour les systèmes de fichiers: https://wiki.postgresql.org/wiki/Foreign_data_wrappers#File_Wrappers

À titre d'exemple, vous pouvez utiliser celui-ci: https://multicorn.readthedocs.org/en/latest/foreign-data-wrappers/fsfdw.html (voir ici pour un bref exemple d'utilisation)

Cela vous donne l'avantage de la cohérence (tous les fichiers liés sont définitivement là) et de tous les autres ACID, alors qu'il y en a encore sur le système de fichiers réel, ce qui signifie que vous pouvez utiliser n'importe quel système de fichiers que vous voulez et que le serveur Web peut les servir directement ( La mise en cache du système d'exploitation s'applique également).

Kenyakorn Ketsombut
la source
1
Merci .. Les wrappers de données étrangères (file_fdw) fournissent-ils un accès en écriture aux images? Je veux stocker des images dans un FileSystem et ses métadonnées dans Postgresql, mais je dois aussi maintenir la cohérence. Avez-vous une solution détaillée? Existe-t-il une autre extension disponible? Multicorn a besoin de python et je préférerais avoir à faire sans utiliser Python ..
Jay Khatwani
1
Oui, ils ont un accès en écriture. Ils sont parfaitement cohérents dans les deux sens. Et non, je ne connais pas de solution égale qui fasse cela sans python.
Kenyakorn Ketsombut
18

Mise à jour à partir de 10 ans plus tard En 2008, les disques durs sur lesquels vous exécuteriez une base de données auraient des caractéristiques très différentes et un coût beaucoup plus élevé que les disques sur lesquels vous stockeriez des fichiers. De nos jours, il existe de bien meilleures solutions pour stocker des fichiers qui n'existaient pas il y a 10 ans et je révoquerais ce conseil et conseillerais aux lecteurs de regarder certaines des autres réponses de ce fil.

Original

Ne stockez pas d'images dans la base de données sauf si vous y êtes obligé. Je comprends qu'il ne s'agit pas d'une application Web, mais s'il n'y a pas d'emplacement de fichier partagé que vous pouvez pointer pour enregistrer l'emplacement du fichier dans la base de données.

//linuxserver/images/imagexxx.jpg

alors peut-être que vous pouvez rapidement configurer un serveur Web et stocker les URL Web dans la base de données (ainsi que le chemin local). Alors que les bases de données peuvent gérer des LOB et 3000 images (4 à 6 mégapixels, en supposant une image de 500 Ko) 1,5 Go n'est pas beaucoup d'espace, les systèmes de fichiers sont bien mieux conçus pour stocker des fichiers volumineux qu'une base de données.

Kris Erickson
la source
15
Mais vous devez trouver un moyen de distribuer les fichiers sur plusieurs répertoires. Les systèmes de fichiers ne sont pas très bons pour stocker des millions de fichiers dans un seul répertoire (en fait, dix milliers sont déjà un problème)
a_horse_with_no_name
1
Ne répond pas à la question initiale. Je cherche personnellement à stocker des images dans Postgres simplement parce que je veux SQL comme couche d'abstraction et que je ne veux pas non plus gérer les fichiers de mon système de fichiers ext4.
sudo
Je suis en conflit, cela ne répond pas à la question, mais je l'ai votée, car c'est une meilleure réponse qu'une réponse à la question.
Andrew Carr
6

Essayez ceci . J'ai utilisé le format LOB (Large Object Binary) pour stocker des documents PDF générés, dont certains avaient une taille de 10+ Mo, dans une base de données et cela a fonctionné à merveille.

Mike Reedell
la source
2

Si vos images sont petites, pensez à les stocker en base64 dans un champ de texte brut.

La raison en est que si base64 a une surcharge de 33%, avec une compression qui disparaît la plupart du temps. (Voir Quelle est la surcharge d'espace du codage Base64? ) Votre base de données sera plus grande, mais les paquets que votre serveur Web envoie au client ne le seront pas. En html, vous pouvez insérer base64 dans une balise <img src = "">, ce qui peut éventuellement simplifier votre application car vous n'aurez pas à servir les images sous forme de fichier binaire dans un navigateur séparé. La gestion des images sous forme de texte simplifie également les choses lorsque vous devez envoyer / recevoir du json, ce qui ne gère pas très bien le binaire.

Oui, je comprends que vous pouvez stocker le binaire dans la base de données et le convertir en / à partir de texte en entrant et en sortant de la base de données, mais parfois les ORM en font un problème. Il peut être plus simple de le traiter comme du texte simple, comme tous vos autres champs.

C'est certainement la bonne façon de gérer les vignettes.

(Les images d'OP ne sont pas petites, ce n'est donc pas vraiment une réponse à sa question.)

ccleve
la source