Przechowywanie obrazów w PostgreSQL

111

W porządku, więc pracuję nad aplikacją, która będzie korzystała z zaplecza Linuksa z PostgreSQL do wyświetlania obrazów na pudełku z systemem Windows z interfejsem napisanym w C # .NET, chociaż front-end nie powinien mieć większego znaczenia. Moje pytanie brzmi:

  • Jaki jest najlepszy sposób na przechowywanie zdjęć w Postgres?

Obrazy mają około 4-6 megapikseli każdy, a my przechowujemy ponad 3000. Warto również zauważyć: to nie jest aplikacja internetowa, będzie najwyżej około dwóch frontonów uzyskujących dostęp do bazy danych jednocześnie.

akdom
źródło

Odpowiedzi:

64

Aktualizacja do 2012 r., Kiedy widzimy, że rozmiary i liczba obrazów rosną i rosną we wszystkich aplikacjach ...

Potrzebujemy pewnego rozróżnienia między „oryginalnym obrazem” a „przetworzonym obrazem”, na przykład miniaturą.

Jak mówi odpowiedź Jcoby'ego, są dwie opcje, więc polecam:

  • użyj blob (Binary Large OBject): do oryginalnego magazynu obrazów, przy stole. Zobacz odpowiedź Ivana (nie ma problemu z tworzeniem kopii zapasowych blobów!), Dodatkowe dostarczone moduły PostgreSQL , instrukcje itp.

  • użyj oddzielnej bazy danych z DBlink : dla oryginalnego magazynu obrazów, w innej (zunifikowanej / wyspecjalizowanej) bazie danych. W tym przypadku wolę bajtę , ale blob jest prawie taki sam. Oddzielenie bazy danych to najlepszy sposób na „ujednoliconą usługę sieciową obrazu”.

  • użyj bajtu (BYTE Array): do buforowania obrazów miniatur. Buforuj małe obrazy, aby szybko wysłać je do przeglądarki internetowej (aby uniknąć problemów z renderowaniem) i zmniejszyć przetwarzanie serwera. Buforuj również istotne metadane, takie jak szerokość i wysokość. Buforowanie bazy danych jest najłatwiejszym sposobem, ale sprawdź swoje potrzeby i konfiguracje serwera (np. Moduły Apache): przechowuj miniatury w systemie plików może być lepsze, porównaj wydajność. Pamiętaj, że jest to (ujednolicona) usługa internetowa, a następnie może być przechowywana w oddzielnej bazie danych (bez kopii zapasowych), obsługującej wiele tabel. Zobacz także podręcznik typów danych binarnych PostgreSQL , testy z kolumną bajtową itp.

UWAGA 1: obecnie używanie „podwójnych rozwiązań” (baza danych + system plików) jest przestarzałe (!). Stosowanie „tylko bazy danych” zamiast podwójnej ma wiele zalet. PostgreSQL ma porównywalną wydajność i dobre narzędzia do eksportu / importu / wejścia / wyjścia.

UWAGA2: pamiętaj, że PostgreSQL ma tylko bajty , nie ma domyślnego BLOBa Oracle : "Standard SQL definiuje (...) BLOB. Format wejściowy różni się od bajtu, ale dostarczone funkcje i operatory są w większości takie same", Manual .


EDYCJA 2014 : Nie zmieniłem dzisiaj oryginalnego tekstu powyżej (moja odpowiedź brzmiała 22 kwietnia 2012, teraz z 14 głosami), otwieram odpowiedź na twoje zmiany (zobacz "Tryb Wiki", możesz edytować!), Do korekty i do aktualizacji .
Pytanie jest stabilne (odpowiedź @ Ivans '08 z 19 głosami), pomóżcie ulepszyć ten tekst.

Peter Krauss
źródło
2
Jakie jest odniesienie do "... użycie" podwójnych rozwiązań "(baza danych + system plików) jest przestarzałe ..."?
dangel
Trochę nowości 2019! Od 2018 roku PostgREST obsługuje bezpośrednie wysyłanie bajtów do sieci. Zobacz tę prostą konfigurację NGINX, aby z niej korzystać. Zobacz przewodnik PostgREST dotyczący wyjścia binarnego
Peter Krauss
52

Odpowiedź Re jcoby'ego:

Bajt będący „zwykłą” kolumną oznacza również, że wartość jest w całości odczytywana do pamięci podczas jej pobierania. Natomiast obiekty blob można przesyłać strumieniowo do standardowego wyjścia. Pomaga to zmniejszyć zużycie pamięci serwera. Szczególnie, gdy przechowujesz obrazy o rozdzielczości 4-6 MPix.

Nie ma problemu z tworzeniem kopii zapasowych obiektów blob. pg_dump udostępnia opcję "-b", która umożliwia dołączenie dużych obiektów do kopii zapasowej.

Więc wolę używać pg_lo_ *, możesz się domyślić.

Odpowiedź Re Kris Erickson:

Powiedziałbym odwrotnie :). Jeśli obrazy nie są jedynymi danymi, które przechowujesz, nie przechowuj ich w systemie plików, chyba że jest to absolutnie konieczne. Taką korzyścią jest mieć zawsze pewność co do spójności danych i mieć dane „w jednym kawałku” (DB). BTW, PostgreSQL świetnie zachowuje spójność.

Jednak, prawda, rzeczywistość często wymaga zbyt dużej wydajności ;-) i popycha cię do obsługi plików binarnych z systemu plików. Ale nawet wtedy staram się używać bazy danych jako "głównej" pamięci dla plików binarnych, ze wszystkimi innymi relacjami konsekwentnie połączonymi, zapewniając jednocześnie mechanizm buforowania oparty na systemie plików w celu optymalizacji wydajności.

Ivan Krechetov
źródło
15
Czy myślisz, że po 10 latach Twoje punkty są nadal ważne? Jakieś aktualizacje od tego czasu?
leventunver
3
@leventunver Nie, punkty, których nie należy trzymać. Na przykład pierwsza o BYTEAbyciu „normalną” kolumną. Postgres od wielu lat obsługuje przesyłanie strumieniowe do / z BYTEAkolumn, co oznacza, że ​​nie musisz przechowywać zawartości w pamięci przed zapisaniem jej w bazie danych.
oligofren
29

W bazie danych są dwie opcje:

  • bajt. Przechowuje dane w kolumnie, eksportowane jako część kopii zapasowej. Używa standardowych funkcji bazy danych do zapisywania i pobierania. Polecane do Twoich potrzeb.
  • plamy. Przechowuje dane na zewnątrz, które normalnie nie są eksportowane jako część kopii zapasowej. Wymaga specjalnych funkcji bazy danych do zapisywania i pobierania.

W przeszłości używałem kolumn bajtowych z dużym powodzeniem, przechowując ponad 10 GB obrazów z tysiącami wierszy. Funkcjonalność TOAST w PG praktycznie neguje wszelkie zalety, jakie mają plamy. W obu przypadkach musisz uwzględnić kolumny metadanych dotyczące nazwy pliku, typu zawartości, wymiarów itp.

jcoby
źródło
1
10 GB to niewiele :-( Szukam rozwiązania TBs
Valentin Heinitz
2
@ValentinHeinitz W przypadku TB, waniliowy Postgres zmaga się nawet z mniejszymi kolumnami tekstu.
sudo
23

Szybka aktualizacja do połowy 2015 r .:

Możesz użyć interfejsu danych obcych Postgres , aby przechowywać pliki w bardziej odpowiedniej bazie danych. Na przykład umieść pliki w GridFS, który jest częścią MongoDB. Następnie użyj https://github.com/EnterpriseDB/mongo_fdw, aby uzyskać do niego dostęp w Postgres.

Ma to zalety, że możesz uzyskać dostęp / odczytać / zapisać / wykonać kopię zapasową w Postrgres i MongoDB, w zależności od tego, co zapewnia większą elastyczność.

Istnieją również obce opakowania danych dla systemów plików: https://wiki.postgresql.org/wiki/Foreign_data_wrappers#File_Wrappers

Jako przykład możesz użyć tego: https://multicorn.readthedocs.org/en/latest/foreign-data-wrappers/fsfdw.html (zobacz tutaj krótki przykład użycia)

Daje to przewagę w postaci spójności (wszystkie połączone pliki na pewno tam są) i wszystkich innych ACID, podczas gdy nadal istnieją w rzeczywistym systemie plików, co oznacza, że ​​możesz używać dowolnego systemu plików, a serwer sieciowy może je obsługiwać bezpośrednio ( Buforowanie systemu operacyjnego ma również zastosowanie).

Kenyakorn Ketsombut
źródło
1
Dzięki ... Czy opakowania danych obcych (file_fdw) zapewniają dostęp do zapisu obrazów? Chcę przechowywać obrazy w systemie plików i jego metadane w Postgresql, ale muszę też zachować spójność. Masz szczegółowe rozwiązanie? Czy jest dostępne inne rozszerzenie? Multicorn potrzebuje Pythona i wolałbym się obejść bez korzystania z Pythona ..
Jay Khatwani
1
Tak, mają prawo do zapisu. Są w pełni spójne w obu kierunkach. I nie, nie znam równego rozwiązania, które robi to bez Pythona.
Kenyakorn Ketsombut
18

Aktualizacja sprzed 10 lat W 2008 r. Dyski twarde, na których będzie można uruchomić bazę danych, będą miały znacznie inne właściwości i znacznie wyższe koszty niż dyski, na których będą przechowywane pliki. W dzisiejszych czasach istnieją znacznie lepsze rozwiązania do przechowywania plików, które nie istniały 10 lat temu, więc odwołałbym tę radę i radziłbym czytelnikom zapoznać się z innymi odpowiedziami w tym wątku.

Oryginalny

Nie przechowuj obrazów w bazie danych, chyba że jest to absolutnie konieczne. Rozumiem, że nie jest to aplikacja internetowa, ale jeśli nie ma udostępnionej lokalizacji pliku, możesz wskazać, aby zapisać lokalizację pliku w bazie danych.

//linuxserver/images/imagexxx.jpg

wtedy możesz szybko skonfigurować serwer sieciowy i przechowywać adresy URL w bazie danych (a także ścieżkę lokalną). Podczas gdy bazy danych mogą obsłużyć LOB i 3000 obrazów (4-6 megapikseli, zakładając 500 KB na obraz) 1,5 gigabajta to niewiele, systemy plików są znacznie lepiej zaprojektowane do przechowywania dużych plików niż baza danych.

Kris Erickson
źródło
15
Ale musisz wymyślić sposób na dystrybucję plików w kilku katalogach. Systemy plików nie są tak dobre, jeśli chodzi o przechowywanie milionów plików w jednym katalogu (w rzeczywistości dziesięć tysięcy to już problem)
a_horse_with_no_name
1
Nie odpowiada na pierwotne pytanie. Osobiście chcę przechowywać obrazy w Postgres tylko dlatego, że chcę SQL jako moją warstwę abstrakcji, a także nie chcę zarządzać plikami w moim systemie plików ext4.
sudo
Jestem skonfliktowany, to nie odpowiada na pytanie, ale zagłosowałem za tym, ponieważ jest to lepsza odpowiedź niż odpowiedź na pytanie.
Andrew Carr,
6

Spróbuj tego . Użyłem formatu Large Object Binary (LOB) do przechowywania wygenerowanych dokumentów PDF, z których niektóre miały rozmiar ponad 10 MB, w bazie danych i działało cudownie.

Mike Reedell
źródło
2

Jeśli Twoje obrazy są małe, rozważ zapisanie ich jako base64 w zwykłym polu tekstowym.

Powodem jest to, że podczas gdy base64 ma narzut na poziomie 33%, przy kompresji, która w większości znika. (Zobacz Jakie jest obciążenie miejsca związane z kodowaniem Base64? ) Twoja baza danych będzie większa, ale pakiety wysyłane przez serwer WWW do klienta nie będą. W html możesz umieścić base64 w tagu <img src = "">, co może uprościć twoją aplikację, ponieważ nie będziesz musiał wyświetlać obrazów jako plików binarnych w osobnym pobieraniu przeglądarki. Obsługa obrazów jako tekstu również upraszcza rzeczy, gdy musisz wysyłać / odbierać json, co nie obsługuje zbyt dobrze plików binarnych.

Tak, rozumiem, że możesz przechowywać plik binarny w bazie danych i konwertować go do / z tekstu podczas wchodzenia i wychodzenia z bazy danych, ale czasami ORMy sprawiają, że jest to kłopotliwe. Może być prostsze traktowanie go jako prostego tekstu, tak jak wszystkie inne pola.

To zdecydowanie właściwy sposób postępowania z miniaturami.

(Obrazy OP nie są małe, więc nie jest to odpowiedź na jego pytanie.)

ccleve
źródło