Armazenamento de imagens em PostgreSQL

111

Tudo bem, então estou trabalhando em um aplicativo que usará um back-end Linux executando PostgreSQL para servir imagens para uma caixa do Windows com o front end escrito em C # .NET, embora o front-end não deva importar. Minha pergunta é:

  • Qual é a melhor maneira de lidar com o armazenamento de imagens no Postgres?

As imagens têm cerca de 4 a 6 megapixels cada, e estamos armazenando mais de 3.000. Também pode ser bom observar: este não é um aplicativo da web, haverá no máximo cerca de dois front-ends acessando o banco de dados ao mesmo tempo.

Akdom
fonte

Respostas:

64

Atualizando para 2012, quando vemos que os tamanhos e a quantidade de imagens estão crescendo cada vez mais, em todas as aplicações ...

Precisamos de alguma distinção entre "imagem original" e "imagem processada", como a miniatura.

Como diz a resposta de Jcoby, há duas opções, então, eu recomendo:

  • use blob (Binary Large OBject): para armazenar imagens originais, na sua mesa. Veja a resposta de Ivan (não há problema em fazer backup de blobs!), Módulos adicionais fornecidos pelo PostgreSQL , instruções etc.

  • use um banco de dados separado com DBlink : para armazenamento de imagem original, em outro banco de dados (unificado / especializado). Nesse caso, prefiro bytea , mas blob é quase o mesmo. Separar o banco de dados é a melhor maneira de um "serviço da web de imagem unificada".

  • use bytea (BYTE Array): para armazenar imagens em miniatura. Armazene as pequenas imagens em cache para enviá-las rapidamente ao navegador da Web (para evitar problemas de renderização) e reduzir o processamento do servidor. Cache também metadados essenciais, como largura e altura. O armazenamento em cache do banco de dados é a maneira mais fácil, mas verifique suas necessidades e configurações do servidor (ex. Módulos do Apache): armazenar miniaturas no sistema de arquivos pode ser melhor, compare o desempenho. Lembre-se de que é um serviço da Web (unificado), então pode ser armazenado em um banco de dados separado (sem backups), atendendo a várias tabelas. Veja também o manual de tipos de dados binários PostgreSQL , testes com coluna bytea , etc.

NOTA 1: hoje o uso de "soluções duplas" (banco de dados + sistema de arquivos) está obsoleto (!). Há muitas vantagens em usar "somente banco de dados" em vez de dual. PostgreSQL tem desempenho comparável e boas ferramentas para exportação / importação / entrada / saída.

NOTA 2: lembre-se de que o PostgreSQL tem apenas bytea , não tem um BLOB Oracle padrão : "O padrão SQL define (...) BLOB. O formato de entrada é diferente de bytea, mas as funções e operadores fornecidos são basicamente os mesmos", Manual .


EDITAR 2014 : Não mudei o texto original acima hoje (minha resposta foi 22 de abril de 12, agora com 14 votos), estou abrindo a resposta para suas alterações (ver "Modo Wiki", você pode editar!), Para revisão e para atualizações .
A questão está estável (resposta de @Ivans '08 com 19 votos), por favor, ajude a melhorar este texto.

Peter Krauss
fonte
2
Qual é a referência para "... o uso de" soluções duplas "(banco de dados + sistema de arquivos) está obsoleto ..."?
dangel de
Algumas notícias de 2019! Desde 2018 o PostgREST oferece suporte à saída direta de bytea para a web. Veja esta configuração simples do NGINX para usá-lo. Consulte o Guia PostgREST sobre a saída binária
Peter Krauss
52

Resposta de Rejoby:

bytea sendo uma coluna "normal" também significa que o valor está sendo lido completamente na memória quando você o busca. Blobs, em contraste, você pode transmitir em stdout. Isso ajuda a reduzir o consumo de memória do servidor. Especialmente, quando você armazena de 4 a 6 imagens MPix.

Não há problema em fazer backup de blobs. O pg_dump fornece a opção "-b" para incluir os objetos grandes no backup.

Então, eu prefiro usar pg_lo_ *, você pode adivinhar.

Resposta de Re Kris Erickson:

Eu diria o contrário :). Quando as imagens não são os únicos dados que você armazena, não as armazene no sistema de arquivos, a menos que seja absolutamente necessário. É um grande benefício estar sempre certo sobre a consistência dos dados e ter os dados "inteiros" (o banco de dados). BTW, PostgreSQL é ótimo em preservar a consistência.

No entanto, é verdade, a realidade costuma exigir muito de desempenho ;-), e força você a servir os arquivos binários do sistema de arquivos. Mas mesmo assim, tendo a usar o banco de dados como o armazenamento "mestre" para binários, com todas as outras relações consistentemente vinculadas, enquanto forneço algum mecanismo de cache baseado em sistema de arquivos para otimização de desempenho.

Ivan Krechetov
fonte
14
Após 10 anos, você acha que seus pontos ainda são válidos? Alguma atualização desde então?
leventunver
3
@leventunver Não, os pontos a não manter. Por exemplo, o primeiro sobre BYTEAser uma coluna "normal". Postgres tem suportado streaming de / para BYTEAcolunas por muitos anos, o que significa que você não precisa armazenar o conteúdo na memória antes de armazená-lo no banco de dados.
oligofren
29

No banco de dados, existem duas opções:

  • tchau. Armazena os dados em uma coluna, exportados como parte de um backup. Usa funções de banco de dados padrão para salvar e recuperar. Recomendado para suas necessidades.
  • bolhas. Armazena os dados externamente, normalmente não exportados como parte de um backup. Requer funções especiais de banco de dados para salvar e recuperar.

Eu usei colunas bytea com grande sucesso no passado, armazenando mais de 10 gb de imagens com milhares de linhas. A funcionalidade TOAST do PG praticamente nega qualquer vantagem que os blobs tenham. Você precisará incluir colunas de metadados em ambos os casos para nome de arquivo, tipo de conteúdo, dimensões, etc.

Jcoby
fonte
1
10 GB não é muito :-( Estou procurando uma solução de TB
Valentin Heinitz
2
@ValentinHeinitz Para TBs, o vanilla Postgres luta mesmo com colunas de texto menores.
sudo
23

Atualização rápida para meados de 2015:

Você pode usar a interface Postgres Foreign Data , para armazenar os arquivos em um banco de dados mais adequado. Por exemplo, coloque os arquivos em um GridFS que faz parte do MongoDB. Em seguida, use https://github.com/EnterpriseDB/mongo_fdw para acessá-lo no Postgres.

Isso tem as vantagens de poder acessar / ler / gravar / fazer backup no Postrgres e no MongoDB, dependendo do que lhe dá mais flexibilidade.

Também existem wrappers de dados externos para sistemas de arquivos: https://wiki.postgresql.org/wiki/Foreign_data_wrappers#File_Wrappers

Como exemplo, você pode usar este: https://multicorn.readthedocs.org/en/latest/foreign-data-wrappers/fsfdw.html (veja aqui um breve exemplo de uso)

Isso lhe dá a vantagem da consistência (todos os arquivos vinculados estão definitivamente lá) e todos os outros ACIDs, enquanto ainda estão no sistema de arquivos real, o que significa que você pode usar qualquer sistema de arquivos que desejar e o servidor da web pode atendê-los diretamente ( O cache do sistema operacional também se aplica).

Kenyakorn Ketsombut
fonte
1
Obrigado .. Os wrappers de dados externos (file_fdw) fornecem acesso de gravação para imagens? Quero armazenar imagens em um FileSystem e seus metadados no Postgresql, mas também preciso manter a consistência. Você tem uma solução detalhada? Existe alguma outra extensão disponível? Multicorn needs python e eu preferiria
ficar
1
Sim, eles têm acesso de gravação. Eles são totalmente consistentes de / em ambas as direções. E não, eu não sei de uma solução igual que faz isso sem python.
Kenyakorn Ketsombut
18

Atualização de 10 anos depois Em 2008, os discos rígidos nos quais você executaria um banco de dados teriam características muito diferentes e um custo muito mais alto do que os discos nos quais você armazenaria os arquivos. Atualmente, existem soluções muito melhores para armazenar arquivos que não existiam há 10 anos e eu revogaria este conselho e aconselharia os leitores a olharem algumas das outras respostas neste tópico.

Original

Não armazene imagens no banco de dados, a menos que seja absolutamente necessário. Eu entendo que este não é um aplicativo da web, mas se não houver um local de arquivo compartilhado que você pode apontar para salvar o local do arquivo no banco de dados.

//linuxserver/images/imagexxx.jpg

então, talvez você possa configurar rapidamente um servidor web e armazenar os urls da web no banco de dados (assim como o caminho local). Embora os bancos de dados possam lidar com LOBs e 3.000 imagens (4-6 megapixels, assumindo 500K por imagem) 1.5 Gigs não é muito, os sistemas de arquivos espaciais são muito mais bem projetados para armazenar arquivos grandes do que um banco de dados.

Kris Erickson
fonte
15
Mas você deve encontrar uma maneira de distribuir os arquivos em vários diretórios. Os sistemas de arquivos não são tão bons em armazenar milhões de arquivos em um único diretório (na verdade, dez milhares já é um problema)
a_horse_with_no_name
1
Não responde à pergunta original. Pessoalmente, estou procurando armazenar imagens no Postgres apenas porque quero SQL como minha camada de abstração e também não quero gerenciar os arquivos em meu sistema de arquivos ext4.
sudo
Estou em conflito, isso não responde a pergunta, mas votei positivamente, porque é uma resposta melhor do que uma resposta à pergunta.
Andrew Carr de
6

Experimente isso . Eu usei o formato Large Object Binary (LOB) para armazenar documentos PDF gerados, alguns dos quais tinham mais de 10 MB de tamanho, em um banco de dados e funcionou maravilhosamente bem.

Mike Reedell
fonte
2

Se suas imagens forem pequenas, considere armazená-las como base64 em um campo de texto simples.

A razão é que enquanto a base64 tem um overhead de 33%, a compactação praticamente desaparece. (Consulte Qual é a sobrecarga de espaço da codificação Base64? ) Seu banco de dados será maior, mas os pacotes que seu servidor envia ao cliente não. Em html, você pode embutir base64 em uma tag <img src = "">, o que pode simplificar seu aplicativo porque você não terá que servir as imagens como binárias em uma busca de navegador separada. Manusear imagens como texto também simplifica as coisas quando você precisa enviar / receber json, o que não lida muito bem com binários.

Sim, eu entendo que você pode armazenar o binário no banco de dados e convertê-lo de / para texto ao entrar e sair do banco de dados, mas às vezes os ORMs tornam isso um incômodo. Pode ser mais simples apenas tratá-lo como um texto simples, como todos os outros campos.

Esta é definitivamente a maneira certa de lidar com miniaturas.

(As imagens de OP não são pequenas, então esta não é realmente uma resposta à sua pergunta.)

ccleve
fonte