Speichern von Bildern in PostgreSQL

111

Okay, ich arbeite an einer Anwendung, die ein Linux-Backend verwendet, auf dem PostgreSQL ausgeführt wird, um Bilder auf einer Windows-Box bereitzustellen, deren Frontend in C # .NET geschrieben ist, obwohl das Frontend kaum eine Rolle spielen sollte. Meine Frage ist:

  • Was ist der beste Weg, um Bilder in Postgres zu speichern?

Die Bilder haben jeweils eine Größe von 4 bis 6 Megapixeln und wir speichern mehr als 3000. Es kann auch sinnvoll sein, dies zu beachten: Dies ist keine Webanwendung, es werden höchstens zwei Front-Ends gleichzeitig auf die Datenbank zugreifen.

Akdom
quelle

Antworten:

64

Aktualisierung auf 2012, wenn wir sehen, dass die Bildgröße und die Anzahl der Bilder in allen Anwendungen immer größer werden ...

Wir brauchen eine Unterscheidung zwischen "Originalbild" und "verarbeitetem Bild", wie zum Beispiel eine Miniaturansicht.

Wie Jcobys Antwort sagt, gibt es zwei Möglichkeiten, die ich empfehle:

  • verwenden Blob (Binary Large Object): für Originalbildspeicher, am Tisch. Siehe Iwans Antwort (kein Problem beim Sichern von Blobs!), PostgreSQL-Zusatzmodule , Anleitungen usw.

  • Verwenden Sie eine separate Datenbank mit DBlink : für den ursprünglichen Bildspeicher in einer anderen (einheitlichen / spezialisierten) Datenbank. In diesem Fall bevorzuge ich Bytea , aber Blob ist fast gleich. Das Trennen der Datenbank ist der beste Weg für einen "einheitlichen Image-Webservice".

  • Verwenden Sie bytea (BYTE Array): zum Zwischenspeichern von Miniaturbildern. Zwischenspeichern Sie die kleinen Bilder, um sie schnell an den Webbrowser zu senden (um Renderingprobleme zu vermeiden) und die Serververarbeitung zu reduzieren. Cache auch wichtige Metadaten wie Breite und Höhe. Das Zwischenspeichern von Datenbanken ist der einfachste Weg. Überprüfen Sie jedoch Ihre Anforderungen und Serverkonfigurationen (z. B. Apache-Module): Das Speichern von Miniaturansichten im Dateisystem ist möglicherweise besser. Vergleichen Sie die Leistung. Denken Sie daran, dass es sich um einen (einheitlichen) Webdienst handelt, der dann in einer separaten Datenbank (ohne Sicherungen) gespeichert werden kann und viele Tabellen bedient. Siehe auch Handbuch für binäre PostgreSQL-Datentypen , Tests mit Bytea-Spalte usw.

HINWEIS 1: Heute ist die Verwendung von "dualen Lösungen" (Datenbank + Dateisystem) veraltet (!). Die Verwendung von "nur Datenbank" anstelle von "dual" bietet viele Vorteile. PostgreSQL bietet eine vergleichbare Leistung und gute Tools für Export / Import / Eingabe / Ausgabe.

HINWEIS 2: Denken Sie daran, dass PostgreSQL nur Bytea und kein Standard- BLOB von Oracle hat : "Der SQL-Standard definiert (...) BLOB. Das Eingabeformat unterscheidet sich von Bytea, aber die bereitgestellten Funktionen und Operatoren sind größtenteils gleich", Manual .


EDIT 2014 : Ich habe den obigen Originaltext heute nicht geändert (meine Antwort war der 22. April 12, jetzt mit 14 Stimmen). Ich öffne die Antwort für Ihre Änderungen (siehe "Wiki-Modus", können Sie bearbeiten!) Zum Korrekturlesen und für Updates .
Die Frage ist stabil (@ Ivans '08 Antwort mit 19 Stimmen), bitte helfen Sie, diesen Text zu verbessern.

Peter Krauss
quelle
2
Was ist die Referenz für "... die Verwendung von" dualen Lösungen "(Datenbank + Dateisystem) ist veraltet ..."?
Dangel
Einige Neuigkeiten für 2019! Seit 2018 unterstützt PostgREST die direkte Ausgabe von bytea ins Web. Sehen Sie sich diese einfache NGINX-Konfiguration an, um sie zu verwenden. Siehe PostgREST-Leitfaden zur Binärausgabe
Peter Krauss
52

Antwort von Re jcoby:

bytea als "normale" Spalte bedeutet auch, dass der Wert beim Abrufen vollständig in den Speicher eingelesen wird. Im Gegensatz dazu können Sie Blobs in stdout streamen. Dies hilft bei der Reduzierung des Speicherbedarfs des Servers. Besonders, wenn Sie 4-6 MPix-Bilder speichern.

Kein Problem beim Sichern von Blobs. pg_dump bietet die Option "-b", um die großen Objekte in die Sicherung aufzunehmen.

Ich bevorzuge also die Verwendung von pg_lo_ *.

Antwort von Re Kris Erickson:

Ich würde das Gegenteil sagen :). Wenn Bilder nicht die einzigen Daten sind, die Sie speichern, speichern Sie sie nicht im Dateisystem, es sei denn, Sie müssen dies unbedingt tun. Es ist von großem Vorteil, immer sicher zu sein, dass Ihre Daten konsistent sind, und die Daten "in einem Stück" (der DB) zu haben. Übrigens ist PostgreSQL hervorragend geeignet, um die Konsistenz zu erhalten.

Allerdings ist die Realität oft zu leistungsintensiv ;-), und Sie müssen die Binärdateien aus dem Dateisystem bereitstellen. Aber selbst dann neige ich dazu, die Datenbank als "Master" -Speicher für Binärdateien zu verwenden, wobei alle anderen Beziehungen konsistent verknüpft sind, und gleichzeitig einen dateisystembasierten Caching-Mechanismus zur Leistungsoptimierung bereitzustellen.

Ivan Krechetov
quelle
14
Denken Sie nach 10 Jahren, dass Ihre Punkte noch gültig sind? Irgendwelche Updates seitdem?
Leventunver
3
@leventunver Nein, die Punkte gelten nicht. Zum Beispiel die erste über BYTEAeine "normale" Spalte. Postgres unterstützt seit vielen Jahren das Streaming zu / von BYTEASpalten, sodass Sie den Inhalt nicht im Speicher speichern müssen, bevor Sie ihn in der Datenbank speichern.
Oligofren
29

In der Datenbank gibt es zwei Möglichkeiten:

  • bytea. Speichert die Daten in einer Spalte, die als Teil einer Sicherung exportiert wird. Verwendet Standarddatenbankfunktionen zum Speichern und Abrufen. Empfohlen für Ihre Bedürfnisse.
  • Blobs. Speichert die Daten extern und wird normalerweise nicht als Teil einer Sicherung exportiert. Erfordert spezielle Datenbankfunktionen zum Speichern und Abrufen.

Ich habe in der Vergangenheit mit großem Erfolg Bytea-Spalten verwendet, um mehr als 10 GB Bilder mit Tausenden von Zeilen zu speichern. Die TOAST-Funktionalität von PG negiert so ziemlich jeden Vorteil, den Blobs haben. In beiden Fällen müssen Sie Metadatenspalten für Dateiname, Inhaltstyp, Abmessungen usw. einfügen.

jcoby
quelle
1
10 GB sind nicht viel :-( Ich suche nach TBs Lösung
Valentin Heinitz
2
@ValentinHeinitz Bei TBs hat Vanilla Postgres auch mit kleineren Textspalten Probleme.
Sudo
23

Schnelles Update bis Mitte 2015:

Sie können die Postgres Foreign Data-Schnittstelle verwenden , um die Dateien in einer geeigneteren Datenbank zu speichern. Legen Sie die Dateien beispielsweise in einem GridFS ab, das Teil von MongoDB ist. Verwenden Sie dann https://github.com/EnterpriseDB/mongo_fdw , um in Postgres darauf zuzugreifen.

Das hat den Vorteil, dass Sie in Postrgres und MongoDB darauf zugreifen / lesen / schreiben / sichern können, je nachdem, was Ihnen mehr Flexibilität gibt.

Es gibt auch fremde Daten-Wrapper für Dateisysteme: https://wiki.postgresql.org/wiki/Foreign_data_wrappers#File_Wrappers

Als Beispiel können Sie dieses verwenden: https://multicorn.readthedocs.org/en/latest/foreign-data-wrappers/fsfdw.html (siehe hier für ein kurzes Anwendungsbeispiel)

Dies gibt Ihnen den Vorteil der Konsistenz (alle verknüpften Dateien sind definitiv vorhanden) und aller anderen ACIDs, während sie sich noch im eigentlichen Dateisystem befinden. Dies bedeutet, dass Sie jedes gewünschte Dateisystem verwenden können und der Webserver sie direkt bereitstellen kann ( OS-Caching gilt auch).

Kenyakorn Ketsombut
quelle
1
Danke. Bieten fremde Daten-Wrapper (file_fdw) Schreibzugriff für Bilder? Ich möchte Bilder in einem Dateisystem und seinen Metadaten in Postgresql speichern, muss aber auch die Konsistenz beibehalten. Haben Sie eine detaillierte Lösung? Gibt es eine andere Erweiterung? Multicorn braucht Python und ich würde es vorziehen, auf Python verzichten zu müssen.
Jay Khatwani
1
Ja, sie haben Schreibzugriff. Sie sind aus / in beide Richtungen völlig konsistent. Und nein, ich kenne keine gleichwertige Lösung, die dies ohne Python schafft.
Kenyakorn Ketsombut
18

Update von 10 Jahren später Im Jahr 2008 hatten die Festplatten, auf denen Sie eine Datenbank ausführen würden, sehr unterschiedliche Eigenschaften und viel höhere Kosten als die Festplatten, auf denen Sie Dateien speichern würden. Heutzutage gibt es viel bessere Lösungen zum Speichern von Dateien, die es vor 10 Jahren noch nicht gab, und ich würde diesen Rat widerrufen und den Lesern raten, sich einige der anderen Antworten in diesem Thread anzusehen.

Original

Speichern Sie keine Bilder in der Datenbank, es sei denn, Sie müssen dies unbedingt tun. Ich verstehe, dass dies keine Webanwendung ist, aber wenn es keinen freigegebenen Dateispeicherort gibt, können Sie darauf verweisen, um den Speicherort der Datei in der Datenbank zu speichern.

//linuxserver/images/imagexxx.jpg

Dann können Sie vielleicht schnell einen Webserver einrichten und die Web-URLs in der Datenbank (sowie den lokalen Pfad) speichern. Während Datenbanken LOBs und 3000 Bilder (4-6 Megapixel, vorausgesetzt 500 KB pro Bild) verarbeiten können, sind 1,5 Gigs nicht viel Speicherplatz. Dateisysteme sind für das Speichern großer Dateien viel besser geeignet als eine Datenbank.

Kris Erickson
quelle
15
Sie müssen jedoch eine Möglichkeit finden, die Dateien auf mehrere Verzeichnisse zu verteilen. Dateisysteme sind nicht so gut darin, Millionen von Dateien in einem einzigen Verzeichnis zu speichern (tatsächlich sind Zehntausende bereits ein Problem)
a_horse_with_no_name
1
Beantwortet die ursprüngliche Frage nicht. Ich persönlich möchte Bilder in Postgres speichern, nur weil ich SQL als Abstraktionsebene verwenden möchte und auch nicht die Dateien in meinem ext4-Dateisystem verwalten möchte.
Sudo
Ich bin in Konflikt geraten, dies beantwortet die Frage nicht, aber ich habe sie positiv bewertet, weil es eine bessere Antwort als eine Antwort auf die Frage ist.
Andrew Carr
6

Versuchen Sie dies . Ich habe das LOB-Format (Large Object Binary) verwendet, um generierte PDF-Dokumente, von denen einige mehr als 10 MB groß waren, in einer Datenbank zu speichern, und es hat wunderbar funktioniert.

Mike Reedell
quelle
2

Wenn Ihre Bilder klein sind, sollten Sie sie als base64 in einem Nur-Text-Feld speichern.

Der Grund dafür ist, dass base64 einen Overhead von 33% hat und die Komprimierung größtenteils wegfällt. (Siehe Wie hoch ist der Speicherplatzaufwand für die Base64-Codierung? ) Ihre Datenbank wird größer, die Pakete, die Ihr Webserver an den Client sendet, jedoch nicht. In HTML können Sie base64 in ein <img src = ""> -Tag einbinden, was möglicherweise Ihre App vereinfachen kann, da Sie die Bilder nicht als Binärdateien in einem separaten Browserabruf bereitstellen müssen. Der Umgang mit Bildern als Text vereinfacht auch das Senden / Empfangen von JSON, was Binärdateien nicht sehr gut handhabt.

Ja, ich verstehe, Sie könnten die Binärdatei in der Datenbank speichern und sie auf dem Weg in und aus der Datenbank in / aus Text konvertieren, aber manchmal machen ORMs dies zu einem Problem. Es kann einfacher sein, es wie alle anderen Felder als geraden Text zu behandeln.

Dies ist definitiv der richtige Weg, um mit Thumbnails umzugehen.

(Die Bilder von OP sind nicht klein, daher ist dies keine wirkliche Antwort auf seine Frage.)

ccleve
quelle