Memorizzazione di immagini in PostgreSQL


111

Va bene, quindi sto lavorando su un'applicazione che utilizzerà un back-end Linux che esegue PostgreSQL per fornire immagini a una macchina Windows con il front-end scritto in C # .NET, anche se il front-end non dovrebbe avere importanza. La mia domanda è:

  • Qual è il modo migliore per gestire l'archiviazione delle immagini in Postgres?

Le immagini misurano circa 4-6 megapixel ciascuna e ne stiamo memorizzando fino a 3000. Potrebbe anche essere utile notare: questa non è un'applicazione web, ci saranno al massimo due front-end che accedono al database contemporaneamente.

Risposte:


64

Aggiornamento al 2012, quando vediamo che le dimensioni delle immagini e il numero di immagini stanno crescendo e crescendo, in tutte le applicazioni ...

Abbiamo bisogno di una distinzione tra "immagine originale" e "immagine elaborata", come la miniatura.

Come dice la risposta di Jcoby, ci sono due opzioni, quindi, consiglio:

  • usa blob (Binary Large OBject): per l'archivio delle immagini originali, al tuo tavolo. Vedi la risposta di Ivan (nessun problema con il backup dei blob!), I moduli aggiuntivi forniti da PostgreSQL , le istruzioni ecc.

  • utilizzare un database separato con DBlink : per l'archivio immagini originale, in un altro database (unificato / specializzato). In questo caso, preferisco bytea , ma il blob è quasi lo stesso. La separazione del database è il modo migliore per un "servizio web di immagini unificato".

  • usa bytea (BYTE Array): per memorizzare nella cache le immagini in miniatura. Memorizza nella cache le piccole immagini per inviarle velocemente al browser web (per evitare problemi di rendering) e ridurre l'elaborazione del server. Cache anche metadati essenziali, come larghezza e altezza. La memorizzazione nella cache del database è il modo più semplice, ma controlla le tue esigenze e le configurazioni del server (es. Moduli Apache): memorizzare le miniature nel file system potrebbe essere migliore, confrontare le prestazioni. Ricorda che si tratta di un servizio web (unificato), quindi può essere archiviato in un database separato (senza backup), che serve molte tabelle. Vedi anche il manuale sui tipi di dati binari di PostgreSQL , i test con la colonna bytea , ecc.

NOTA1: oggi l'uso di "soluzioni doppie" (database + filesystem) è deprecato (!). Ci sono molti vantaggi nell'usare "solo database" invece di dual. PostgreSQL ha prestazioni comparabili e buoni strumenti per esportazione / importazione / input / output.

NOTA 2: ricorda che PostgreSQL ha solo bytea , non ha un BLOB Oracle predefinito : "Lo standard SQL definisce (...) BLOB. Il formato di input è diverso da bytea, ma le funzioni e gli operatori forniti sono per lo più gli stessi", Manuale .


EDIT 2014 : oggi non ho cambiato il testo originale sopra (la mia risposta è stata 22 aprile '12, ora con 14 voti), sto aprendo la risposta per le tue modifiche (vedi "Modalità Wiki", puoi modificare!), Per la correzione di bozze e per gli aggiornamenti .
La domanda è stabile (risposta '08 di @ Ivans con 19 voti), per favore, aiutaci a migliorare questo testo.


2
Qual è il riferimento per "... l'uso di" soluzioni doppie "(database + filesystem) è deprecato ..."?
dangel

Alcune novità del 2019! Dal 2018 PostgREST supporta l'output diretto di bytea sul web. Vedi questa semplice configurazione di NGINX per usarla. Vedi la guida PostgREST sull'output binario
Peter Krauss

52

La risposta di Re jcoby:

bytea essendo una colonna "normale" significa anche che il valore viene letto completamente in memoria quando lo prendi. Blob, al contrario, puoi eseguire lo streaming in stdout. Ciò aiuta a ridurre l'impronta di memoria del server. Soprattutto quando si memorizzano 4-6 immagini MPix.

Nessun problema con il backup dei BLOB. pg_dump fornisce l'opzione "-b" per includere gli oggetti di grandi dimensioni nel backup.

Quindi, preferisco usare pg_lo_ *, potresti indovinare.

La risposta di Re Kris Erickson:

Direi il contrario :). Quando le immagini non sono gli unici dati che memorizzi, non archiviarle nel file system a meno che non sia assolutamente necessario. È un tale vantaggio essere sempre sicuri della coerenza dei dati e avere i dati "in un unico pezzo" (il DB). A proposito, PostgreSQL è ottimo per preservare la coerenza.

Tuttavia, è vero, la realtà è spesso troppo esigente in termini di prestazioni ;-) e ti spinge a servire i file binari dal file system. Ma anche in questo caso tendo a utilizzare il DB come memoria "principale" per i binari, con tutte le altre relazioni collegate in modo coerente, fornendo allo stesso tempo un meccanismo di memorizzazione nella cache basato sul file system per l'ottimizzazione delle prestazioni.


14
Dopo 10 anni, pensi che i tuoi punti siano ancora validi? Qualche aggiornamento da allora?
leventunver

3
@leventunver No, i punti da non tenere. Ad esempio il primo BYTEAsull'essere una colonna "normale". Postgres supporta lo streaming da / verso le BYTEAcolonne da molti anni, il che significa che non è necessario archiviare i contenuti in memoria prima di archiviarli nel db.
oligofren

29

Nel database ci sono due opzioni:

  • bytea. Memorizza i dati in una colonna, esportati come parte di un backup. Utilizza le funzioni di database standard per salvare e recuperare. Consigliato per le tue esigenze.
  • blob. Memorizza i dati esternamente, normalmente non esportati come parte di un backup. Richiede funzioni di database speciali per salvare e recuperare.

Ho usato le colonne bytea con grande successo in passato memorizzando 10 + GB di immagini con migliaia di righe. La funzionalità TOAST di PG nega praticamente qualsiasi vantaggio offerto dai blob. Dovrai includere colonne di metadati in entrambi i casi per nome file, tipo di contenuto, dimensioni, ecc.


1
10 GB non sono molti :-( Sto cercando una soluzione TB
Valentin Heinitz

2
@ValentinHeinitz Per le TB, Vanilla Postgres fatica anche con colonne di testo più piccole.
sudo

23

Aggiornamento rapido a metà 2015:

È possibile utilizzare l' interfaccia di Postgres Foreign Data , per memorizzare i file nel database più adatto. Ad esempio, metti i file in un GridFS che fa parte di MongoDB. Quindi usa https://github.com/EnterpriseDB/mongo_fdw per accedervi in ​​Postgres.

Questo ha i vantaggi, che puoi accedere / leggere / scrivere / eseguire il backup in Postrgres e MongoDB, a seconda di ciò che ti offre maggiore flessibilità.

Esistono anche wrapper di dati esterni per i file system: https://wiki.postgresql.org/wiki/Foreign_data_wrappers#File_Wrappers

Come esempio puoi usare questo: https://multicorn.readthedocs.org/en/latest/foreign-data-wrappers/fsfdw.html (vedi qui per un breve esempio di utilizzo)

Ciò ti offre il vantaggio della coerenza (tutti i file collegati sono sicuramente presenti) e di tutti gli altri ACID, mentre sono ancora presenti nel file system effettivo, il che significa che puoi utilizzare qualsiasi file system desideri e il server web può servirli direttamente ( Si applica anche la memorizzazione nella cache del sistema operativo).


1
Grazie .. I wrapper di dati esterni (file_fdw) forniscono l'accesso in scrittura per le immagini? Voglio memorizzare le immagini in un FileSystem e i suoi metadati in Postgresql, ma devo anche mantenere la coerenza. Hai una soluzione dettagliata? Sono disponibili altre estensioni? Multicorn ha bisogno di Python e preferirei dover fare a meno di usare Python ..
Jay Khatwani

1
Sì, hanno accesso in scrittura. Sono completamente coerenti da / in entrambe le direzioni. E no, non conosco una soluzione uguale che lo faccia senza Python.
Kenyakorn Ketsombut

18

Aggiornamento da 10 anni dopo Nel 2008 i dischi rigidi su cui eseguiresti un database avrebbero caratteristiche molto diverse e un costo molto più elevato rispetto ai dischi su cui archiviare i file. Oggigiorno ci sono soluzioni molto migliori per archiviare file che non esistevano 10 anni fa e revocherei questo consiglio e consiglierei ai lettori di guardare alcune delle altre risposte in questo thread.

Originale

Non memorizzare nelle immagini nel database a meno che non sia assolutamente necessario. Capisco che questa non è un'applicazione web, ma se non c'è un percorso di file condiviso che puoi puntare per salvare il percorso del file nel database.

//linuxserver/images/imagexxx.jpg

allora forse puoi configurare rapidamente un server web e memorizzare gli URL web nel database (così come il percorso locale). Sebbene i database possano gestire LOB e 3000 immagini (4-6 Megapixel, supponendo 500K un'immagine) 1.5 Gigs non è molto spazio, i file system sono molto meglio progettati per l'archiviazione di file di grandi dimensioni rispetto a un database.


15
Ma devi trovare un modo per distribuire i file su più directory. I filesystem non sono così bravi a memorizzare milioni di file in una singola directory (in realtà dieci migliaia sono già un problema)
a_horse_with_no_name

1
Non risponde alla domanda originale. Personalmente sto cercando di archiviare immagini in Postgres solo perché voglio SQL come livello di astrazione e inoltre non voglio gestire i file nel mio filesystem ext4.
sudo

Sono in conflitto, questo non risponde alla domanda, ma l'ho votato positivamente, perché è una risposta migliore di una risposta alla domanda.
Andrew Carr,

6

Prova questo . Ho utilizzato il formato LOB (Large Object Binary) per archiviare i documenti PDF generati, alcuni dei quali avevano una dimensione di oltre 10 MB, in un database e ha funzionato meravigliosamente.


2

Se le tue immagini sono piccole, considera di memorizzarle come base64 in un campo di testo normale.

Il motivo è che mentre base64 ha un overhead del 33%, con la compressione che per lo più scompare. (Vedi Qual è l'overhead di spazio della codifica Base64? ) Il tuo database sarà più grande, ma i pacchetti che il tuo server web invia al client non lo saranno. In html, puoi incorporare base64 in un tag <img src = "">, il che può eventualmente semplificare la tua app perché non dovrai offrire le immagini come binarie in un browser separato. Gestire le immagini come testo semplifica anche le cose quando devi inviare / ricevere json, che non gestisce molto bene il binario.

Sì, capisco che potresti memorizzare il binario nel database e convertirlo in / da testo entrando e uscendo dal database, ma a volte gli ORM lo rendono una seccatura. Può essere più semplice trattarlo come testo semplice come tutti gli altri campi.

Questo è sicuramente il modo giusto per gestire le miniature.

(Le immagini di OP non sono piccole, quindi questa non è davvero una risposta alla sua domanda.)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.