在PostgreSQL中存储图像


111

好吧,所以我正在开发一个应用程序,该应用程序将使用运行PostgreSQL的Linux后端将图像用前端用C#.NET编写到Windows盒中,尽管前端几乎没有关系。我的问题是:

  • 在Postgres中处理图像的最佳方法是什么?

这些图像每个约为4-6兆像素,我们存储的图像多达3000个。可能还需要注意:这不是一个Web应用程序,最多将有大约两个前端同时访问数据库。

Answers:


64

更新到2012年,当我们看到在所有应用程序中图像尺寸和图像数量都在不断增长时...

我们需要区分“原始图像”和“处理后的图像”,例如缩略图。

正如Jcoby的回答所言,那么有两种选择,我建议:

  • 使用Blob(二进制大对象):用于原始图像存储,在您的桌子上。见伊万的回答(用备份的斑点没问题!),PostgreSQL的额外供电的模块如何渡等。

  • 使用DBlink单独的数据库:用于原始图像存储,位于另一个(统一/专业化)数据库。在这种情况下,我更喜欢bytea,但blob 几乎相同。分离数据库是“统一图像Web服务”的最佳方法。

  • 使用BYtea(BYTE Array):用于缓存缩略图。缓存少量图像以将其快速发送到Web浏览器(以避免呈现问题)并减少服务器处理。缓存基本元数据,例如宽度和高度。数据库缓存是最简单的方法,但是检查您的需求和服务器配置(例如Apache模块):将缩略图存储在文件系统中可能会更好,比较性能。请记住,它是一个(统一的)Web服务,然后可以存储在一个单独的数据库中(没有备份),该数据库可以服务许多表。另请参见PostgreSQL二进制数据类型手册使用bytea列进行测试等。

注意1:今天不建议使用“双重解决方案”(数据库+文件系统)。使用“仅数据库”而不是双重使用有很多优点。PostgreSQL具有可比的性能和用于导出/导入/输入/输出的良好工具。

注意2:请记住PostgreSQL仅具有bytea,而没有默认的Oracle BLOB:“ SQL标准定义了(...)BLOB。输入格式与bytea不同,但是提供的函数和运算符基本相同”,Manual


EDIT 2014:今天我没有更改上面的原始文本(我的回答是12年12月22日,现在以14票),我正在打开您所做更改的答案 (请参阅“ Wiki模式”,您可以编辑!),以便进行校对更新
这个问题很稳定(@Ivans的'08答案为19票),请帮助改善本文。


2
“ ...不建议使用“双重解决方案”(数据库+文件系统)...”的引用是什么?
dangel '19

一些2019年新闻! 自2018 PostgREST支持直接输出BYTEA到网上。请参阅此NGINX简单配置以使用它。见PostgREST指南二进制输出
彼得·克劳斯

52

关于jcoby的回答:

bytea为“正常”列也意味着在您获取值时,该值已完全读入内存。相反,Blob可以流到stdout中。这有助于减少服务器内存占用。特别是当您存储4-6个MPix图像时。

备份Blob没问题。pg_dump提供了“ -b”选项,以将大对象包括到备份中。

因此,您可能会猜测,我更喜欢使用pg_lo_ *。

关于克里斯·埃里克森的回答:

我会说相反的话:)。当图像不是您唯一存储的数据时,除非绝对必要,否则不要将它们存储在文件系统中。始终确保您的数据一致性并将数据“合为一体”(数据库)是非常有益的。顺便说一句,PostgreSQL在保持一致性方面很棒。

但是,确实,现实往往对性能要求很高;-)会迫使您从文件系统提供二进制文件。但是即使那样,我仍然倾向于使用DB作为二进制文件的“主”存储,所有其他关系始终保持链接,同时提供一些基于文件系统的缓存机制来优化性能。


14
十年后,您认为您的积分仍然有效吗?从那以后有什么更新吗?
leventunver

3
@leventunver不,要点不成立。例如,第一个关于BYTEA“普通”列。Postgres多年来一直支持到列的流传输BYTEA,这意味着您不必在将内容存储在数据库中之前将其存储在内存中。
oligofren

29

在数据库中,有两个选项:

  • bytea。将数据存储在列中,作为备份的一部分导出。使用标准数据库功能进行保存和检索。根据您的需求推荐。
  • 斑点 将数据存储在外部,通常不作为备份的一部分导出。需要特殊的数据库功能才能保存和检索。

过去,我使用bytea列取得了巨大的成功,可存储10 + gb的图像并具有数千行。PG的TOAST功能几乎抵消了Blob具有的任何优势。无论哪种情况,您都需要包含元数据列,以用于文件名,内容类型,尺寸等。


1
10GB并不多:-(我正在寻找TB解决方案
Valentin Heinitz

2
@ValentinHeinitz对于结核病,即使使用较小的文本列,香草Postgres仍在挣扎。
sudo

23

快速更新到2015年中期:

您可以使用Postgres Foreign Data接口,将文件存储在更合适的数据库中。例如,将文件放在MongoDB的GridFS中。然后使用 https://github.com/EnterpriseDB/mongo_fdw 在Postgres中访问它。

这样做的好处是,您可以在Postrgres和MongoDB中访问/读取/写入/备份它,这取决于赋予您更多灵活性的原因。

还有用于文件系统的外部数据包装器: https : //wiki.postgresql.org/wiki/Foreign_data_wrappers#File_Wrappers

作为示例,您可以使用以下示例:https : //multicorn.readthedocs.org/en/latest/foreign-data-wrappers/fsfdw.html (有关简单用法示例,请参见此处)

这为您提供了一致性(所有链接的文件都肯定存在)和所有其他ACID的优点,而实际文件系统中仍然存在这些文件,这意味着您可以使用所需的任何文件系统,并且Web服务器可以直接为它们提供服务(操作系统缓存也适用)。


1
谢谢..外部数据包装器(file_fdw)是否提供图像的写访问权限?我想在Postgresql中将图像存储到FileSystem及其元数据,但是我也必须保持一致性。您有详细的解决方案吗?还有其他扩展名吗?Multicorn需要Python和我宁愿不必做,而不使用Python ..
杰伊Khatwani

1
是的,他们具有写访问权限。它们在两个方向上都完全一致。不,我不知道没有python就能做到的平等解决方案。
Kenyakorn Ketsombut

18

十年后的更新 在2008年,您要在其上运行数据库的硬盘驱动器将具有与要在其上存储文件的磁盘不同的特性,并且成本要高得多。如今,有更好的解决方案来存储10年前不存在的文件,我将撤销此建议,并建议读者查看此主题中的其他一些答案。

原版的

除非绝对必要,否则不要将其存储在数据库的图像中。我知道这不是Web应用程序,但是如果没有共享的文件位置,则可以指向将文件的位置保存在数据库中。

//linuxserver/images/imagexxx.jpg

那么也许您可以快速设置Web服务器并将Web网址存储在数据库中(以及本地路径)。尽管数据库可以处理LOB和3000张图像(4-6兆像素,假设500K图像),但1.5 Gig并不是很多空间文件系统比数据库更适合存储大型文件。


15
但是您必须想出一种在多个目录中分发文件的方法。文件系统不能很好地在单个目录中存储数百万个文件(实际上成千上万个问题)
a_horse_with_no_name 2013年

1
不回答原始问题。我个人希望将图像存储在Postgres中只是因为我希望将SQL作为我的抽象层,而且也不想管理ext4文件系统中的文件。
sudo

我很矛盾,这不能回答问题,但是我赞成,因为它比对问题的回答更好。
安德鲁·卡尔

6

试试这个。我已经使用大对象二进制(LOB)格式在数据库中存储生成的PDF文档,其中一些文件大小超过10 MB。


2

如果图像较小,请考虑将它们作为base64存储在纯文本字段中。

原因是,尽管base64的开销为33%,但压缩几乎消失了。(请参阅Base64编码的空间开销是多少?)您的数据库将更大,但您的Web服务器发送给客户端的数据包将不会更大。在html中,您可以在<img src =“”>标记中内联base64,这可以简化您的应用程序,因为您不必在单独的浏览器访存中将图像作为二进制文件提供。当您必须发送/接收json时,将图像作为文本处理还可以简化事情,而json不能很好地处理二进制文件。

是的,我知道您可以将二进制文件存储在数据库中,并在进出数据库的过程中将其转换为文本或从文本转换为文本,但是有时ORM会带来麻烦。像对待所有其他字段一样,将其视为纯文本可能会更简单。

这绝对是处理缩略图的正确方法。

(OP的图像并不小,因此这并不是他问题的答案。)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.