Almacenamiento de imágenes en PostgreSQL

111

Muy bien, estoy trabajando en una aplicación que usará un back-end de Linux que ejecute PostgreSQL para entregar imágenes a un cuadro de Windows con el front-end escrito en C # .NET, aunque el front-end apenas debería importar. Mi pregunta es:

  • ¿Cuál es la mejor manera de lidiar con el almacenamiento de imágenes en Postgres?

Las imágenes tienen alrededor de 4 a 6 megapíxeles cada una, y estamos almacenando más de 3000. También sería bueno tener en cuenta: esta no es una aplicación web, como mucho habrá dos interfaces que accedan a la base de datos a la vez.

akdom
fuente

Respuestas:

64

Actualizando a 2012, cuando vemos que los tamaños de imagen, y la cantidad de imágenes, están creciendo y creciendo, en todas las aplicaciones ...

Necesitamos alguna distinción entre "imagen original" e "imagen procesada", como miniatura.

Como dice la respuesta de Jcoby, hay dos opciones, entonces, recomiendo:

  • use blob (Binary Large OBject): para almacenar imágenes originales, en su mesa. Vea la respuesta de Ivan (¡no hay problema con la copia de seguridad de blobs!), Los módulos adicionales suministrados por PostgreSQL , los procedimientos, etc.

  • use una base de datos separada con DBlink : para el almacenamiento de imágenes originales, en otra base de datos (unificada / especializada). En este caso, prefiero bytea , pero blob es casi igual. La separación de la base de datos es la mejor manera de tener un "servicio web de imágenes unificadas".

  • use bytea (BYTE Array): para almacenar en caché imágenes en miniatura. Guarde en caché las pequeñas imágenes para enviarlas rápidamente al navegador web (para evitar problemas de renderizado) y reducir el procesamiento del servidor. Almacene en caché también metadatos esenciales, como ancho y alto. El almacenamiento en caché de la base de datos es la forma más fácil, pero verifique sus necesidades y la configuración del servidor (por ejemplo, módulos Apache): almacenar miniaturas en el sistema de archivos puede ser mejor, compare el rendimiento. Recuerde que es un servicio web (unificado), luego se puede almacenar en una base de datos separada (sin copias de seguridad), sirviendo muchas tablas. Consulte también el manual de tipos de datos binarios de PostgreSQL , pruebas con columna bytea , etc.

NOTA 1: hoy en día, el uso de "soluciones duales" (base de datos + sistema de archivos) está en desuso (!). Hay muchas ventajas de usar "solo base de datos" en lugar de dual. PostgreSQL tiene un rendimiento comparable y buenas herramientas para exportación / importación / entrada / salida.

NOTA 2: recuerde que PostgreSQL solo tiene bytea , no tiene un BLOB predeterminado de Oracle : "El estándar SQL define (...) BLOB. El formato de entrada es diferente de bytea, pero las funciones y operadores provistos son en su mayoría los mismos", Manual .


EDITAR 2014 : Hoy no he cambiado el texto original anterior (mi respuesta fue el 22 de abril de 2012, ahora con 14 votos), estoy abriendo la respuesta para sus cambios (consulte "Modo Wiki", ¡puede editar!), Para corregir y para actualizaciones .
La pregunta es estable (respuesta de @Ivans '08 con 19 votos), por favor, ayude a mejorar este texto.

Peter Krauss
fuente
2
¿Cuál es la referencia para "... el uso de" soluciones duales "(base de datos + sistema de archivos) está en desuso ..."?
Peligroso
¡Algunas novedades de 2019! Desde 2018, PostgREST admite la salida directa de bytea a la web. Vea esta configuración simple de NGINX para usarla. Consulte la guía PostgREST sobre salida binaria
Peter Krauss
52

La respuesta de re jcoby:

bytea es una columna "normal" también significa que el valor se lee completamente en la memoria cuando lo recuperas. Blobs, por el contrario, puede transmitir a stdout. Eso ayuda a reducir la huella de memoria del servidor. Especialmente, cuando almacena imágenes de 4-6 MPix.

No hay problema con realizar copias de seguridad de blobs. pg_dump proporciona la opción "-b" para incluir los objetos grandes en la copia de seguridad.

Entonces, prefiero usar pg_lo_ *, puedes adivinar.

Respuesta de Kris Erickson:

Yo diría lo contrario :). Cuando las imágenes no son los únicos datos que almacena, no las almacene en el sistema de archivos a menos que sea absolutamente necesario. Es un gran beneficio estar siempre seguro de la consistencia de sus datos y tener los datos "en una sola pieza" (la base de datos). Por cierto, PostgreSQL es excelente para preservar la coherencia.

Sin embargo, es cierto que la realidad a menudo exige demasiado rendimiento ;-), y te empuja a servir los archivos binarios desde el sistema de archivos. Pero incluso entonces tiendo a usar la base de datos como el almacenamiento "maestro" para los binarios, con todas las demás relaciones vinculadas de manera coherente, al tiempo que proporciono algún mecanismo de almacenamiento en caché basado en el sistema de archivos para optimizar el rendimiento.

Ivan Krechetov
fuente
14
Después de 10 años, ¿cree que sus puntos siguen siendo válidos? ¿Alguna actualización desde entonces?
Leventunver
3
@leventunver No, los puntos para no aguantar. Por ejemplo, el primero sobre BYTEAser una columna "normal". Postgres ha admitido la transmisión desde / hacia BYTEAcolumnas durante muchos años, lo que significa que no tiene que almacenar el contenido en la memoria antes de almacenarlo en la base de datos.
oligofren
29

En la base de datos, hay dos opciones:

  • bytea. Almacena los datos en una columna, exportados como parte de una copia de seguridad. Utiliza funciones de base de datos estándar para guardar y recuperar. Recomendado para sus necesidades.
  • manchas. Almacena los datos de forma externa, que normalmente no se exportan como parte de una copia de seguridad. Requiere funciones especiales de base de datos para guardar y recuperar.

He usado columnas bytea con gran éxito en el pasado almacenando más de 10 gb de imágenes con miles de filas. La funcionalidad TOAST de PG prácticamente niega cualquier ventaja que tengan los blobs. Deberá incluir columnas de metadatos en cualquier caso para nombre de archivo, tipo de contenido, dimensiones, etc.

jcoby
fuente
1
10GB no es mucho :-( Estoy buscando una solución de TB
Valentin Heinitz
2
@ValentinHeinitz Para los TB, Vanilla Postgres lucha incluso con columnas de texto más pequeñas.
sudo
23

Actualización rápida a mediados de 2015:

Puede utilizar la interfaz de datos externos de Postgres para almacenar los archivos en una base de datos más adecuada. Por ejemplo, coloque los archivos en un GridFS que es parte de MongoDB. Luego use https://github.com/EnterpriseDB/mongo_fdw para acceder a él en Postgres.

Eso tiene las ventajas de que puede acceder / leer / escribir / respaldarlo en Postrgres y MongoDB, dependiendo de lo que le brinde más flexibilidad.

También hay contenedores de datos externos para sistemas de archivos: https://wiki.postgresql.org/wiki/Foreign_data_wrappers#File_Wrappers

Como ejemplo, puede usar este: https://multicorn.readthedocs.org/en/latest/foreign-data-wrappers/fsfdw.html (vea aquí un breve ejemplo de uso)

Eso le da la ventaja de la consistencia (todos los archivos vinculados definitivamente están allí) y todos los demás ACID, mientras todavía están en el sistema de archivos real, lo que significa que puede usar cualquier sistema de archivos que desee y el servidor web puede servirlos directamente ( El almacenamiento en caché del sistema operativo también se aplica).

Kenyakorn Ketsombut
fuente
1
Gracias ... ¿Los contenedores de datos externos (file_fdw) proporcionan acceso de escritura a las imágenes? Quiero almacenar imágenes en un FileSystem y sus metadatos en Postgresql, pero también tengo que mantener la consistencia. ¿Tiene una solución detallada? ¿Hay alguna otra extensión disponible? Multicorn necesita Python y preferiría tener que prescindir de Python ..
Jay Khatwani
1
Sí, tienen acceso de escritura. Son completamente consistentes desde / en ambas direcciones. Y no, no conozco una solución igual que haga esto sin Python.
Kenyakorn Ketsombut
18

Actualización de 10 años después En 2008, los discos duros en los que ejecutaría una base de datos tendrían características muy diferentes y un costo mucho más alto que los discos en los que almacenaría archivos. En estos días, hay soluciones mucho mejores para almacenar archivos que no existían hace 10 años y yo revocaría este consejo y recomendaría a los lectores que miren algunas de las otras respuestas en este hilo.

Original

No almacene imágenes en la base de datos a menos que sea absolutamente necesario. Entiendo que esta no es una aplicación web, pero si no hay una ubicación de archivo compartido que puede señalar para guardar la ubicación del archivo en la base de datos.

//linuxserver/images/imagexxx.jpg

entonces quizás pueda configurar rápidamente un servidor web y almacenar las URL web en la base de datos (así como la ruta local). Si bien las bases de datos pueden manejar LOB y 3000 imágenes (4-6 megapíxeles, asumiendo 500K una imagen) 1.5 Gigs no es mucho espacio, los sistemas de archivos están mucho mejor diseñados para almacenar archivos grandes que una base de datos.

Kris Erickson
fuente
15
Pero debe encontrar una forma de distribuir los archivos en varios directorios. Los sistemas de ficheros no son tan buenos en el almacenamiento de millones de archivos en un solo directorio (miles realidad diez ya es un problema)
a_horse_with_no_name
1
No responde a la pregunta original. Personalmente, estoy buscando almacenar imágenes en Postgres solo porque quiero SQL como mi capa de abstracción y tampoco quiero administrar los archivos en mi sistema de archivos ext4.
sudo
Estoy en conflicto, esto no responde a la pregunta, pero voté a favor porque es una mejor respuesta que una respuesta a la pregunta.
Andrew Carr
6

Prueba esto . He usado el formato Large Object Binary (LOB) para almacenar documentos PDF generados, algunos de los cuales tenían más de 10 MB de tamaño, en una base de datos y funcionó de maravilla.

Mike Reedell
fuente
2

Si sus imágenes son pequeñas, considere almacenarlas como base64 en un campo de texto sin formato.

La razón es que mientras base64 tiene una sobrecarga del 33%, la compresión desaparece en su mayoría. (Consulte ¿Cuál es la sobrecarga de espacio de la codificación Base64? ) Su base de datos será más grande, pero los paquetes que su servidor web envía al cliente no lo serán. En html, puede insertar base64 en una etiqueta <img src = "">, lo que posiblemente pueda simplificar su aplicación porque no tendrá que mostrar las imágenes como binarias en una búsqueda separada del navegador. El manejo de imágenes como texto también simplifica las cosas cuando tiene que enviar / recibir json, que no maneja muy bien los binarios.

Sí, tengo entendido que podría almacenar el binario en la base de datos y convertirlo a / desde texto al entrar y salir de la base de datos, pero a veces los ORM hacen que eso sea una molestia. Puede ser más sencillo tratarlo como texto simple como todos los demás campos.

Esta es definitivamente la forma correcta de manejar las miniaturas.

(Las imágenes de OP no son pequeñas, por lo que esta no es realmente una respuesta a su pregunta).

ccleve
fuente