在PostgreSQL中存储图像

akd*_*dom 99 postgresql image

好吧,所以我正在开发一个应用程序,它将使用运行PostgreSQL的Linux后端将图像提供给Windows框,前端用C#.NET编写,尽管前端应该不重要.我的问题是:

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

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

Pet*_*uss 54

更新到2012年,当我们看到图像大小和图像数量正在增长和增长时,在所有应用程序中......

我们需要区分"原始图像"和"已处理图像",如缩略图.

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

  • 使用blob(Binary Large OBject):用于原始图像存储,在您的桌子上.请参阅Ivan的答案(备份blob没问题!),PostgreSQL附加提供的模块,How-to等.

  • 使用与DBlink单独的数据库:用于原始图像存储,在另一个(统一/专用)数据库.在这种情况下,我preffer bytea,但blob 几乎相同.分离数据库是"统一图像Web服务"的最佳方式.

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

注1:今天不推荐使用"双解决方案"(数据库+文件系统)(!).使用"仅数据库"代替双重有许多优点.PostgreSQL具有可比性能和出口/导入/输入/输出的良好工具.

注意2:记住PostgreSQL只有bytea,没有默认的Oracle BLOB:"SQL标准定义(...)BLOB.输入格式与bytea不同,但提供的函数和运算符大致相同",Manual.


编辑2014:我今天没有更改原文(我的答案是12月4日,现在有14票),我正在为你的更改打开答案 (参见"Wiki模式",你可以编辑!),用于校对更新.
问题是稳定的(@Ivans '08回答19票),请帮助改进这个文本.

  • “ ...不建议使用“双重解决方案”(数据库+文件系统)...”的引用是什么? (2认同)
  • 一些2019年的新闻![自 2018 年起](https://github.com/PostgREST/postgrest/pull/802) PostgREST 支持将 *bytea* 直接输出到网络。请参阅[NGINX简单配置](https://github.com/PostgREST/postgrest/pull/802#issuecomment-280864615)来使用它。请参阅[关于二进制输出的PostgREST指南](http://postgrest.org/en/v6.0/api.html#binary-output) (2认同)

Iva*_*tov 52

Re jcoby的回答:

bytea是一个"普通"列,也意味着当你获取它时,该值被完全读入内存.相比之下,Blob可以流入stdout.这有助于减少服务器内存占用.特别是,当您存储4-6个MPix图像时.

备份blob没问题.pg_dump提供"-b"选项以将大对象包含在备份中.

所以,我更喜欢使用pg_lo_*,你可能会猜.

Re Kris Erickson的回答:

我会说相反的:).当图像不是您存储的唯一数据时,请不要将它们存储在文件系统上,除非您绝对必须这样做.始终确保数据一致性并将数据"整体"(数据库)保持这样的好处.顺便说一句,PostgreSQL非常适合保持一致性.

但是,事实上,现实往往性能要求太高;-),它会促使您从文件系统中提供二进制文件.但即便如此,我倾向于使用DB作为二进制文件的"主"存储,所有其他关系一致地链接,同时提供一些基于文件系统的缓存机制以进行性能优化.

  • 10年后,您认为您的积分仍然有效吗?从那时起的任何更新? (14认同)
  • @leventunver不,要点不成立。例如,关于“ BYTEA”的第一个是“正常”列。Postgres支持_BYTEA列到/从BYTEA列的流已经很多年了,这意味着您不必在将内容存储在数据库中之前将其存储在内存中。 (3认同)

jco*_*oby 26

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

  • BYTEA.将数据存储在列中,作为备份的一部分导出.使用标准数据库函数进行保存和检索.建议您的需求.
  • 斑点.在外部存储数据,通常不作为备份的一部分导出.需要特殊的数据库函数来保存和检索.

我在过去使用了bytea列并取得了巨大的成功,可以存储数千行的10 + gb图像.PG的TOAST功能几乎否定了blob的任何优势.对于文件名,内容类型,维度等,您需要在两种情况下都包含元数据列.

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

Ken*_*but 21

快速更新至2015年中:

您可以使用Postgres Foreign Data接口将文件存储在更合适的数据库中.例如,将文件放在GridFS中,这是MongoDB的一部分.然后使用 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服务器可以直接为它们提供服务(操作系统缓存也适用).

  • 是的,他们有写权限。它们在两个方向上都完全一致。不,我不知道有没有同样的解决方案可以在不使用 python 的情况下完成此操作。 (2认同)

Kri*_*son 17

10年后的更新 2008年,运行数据库的硬盘驱动器的特性会比存储文件的磁盘高得多,而且成本也要高得多.现在有更好的解决方案来存储10年前不存在的文件,我会撤销这个建议,并建议读者在这个帖子中查看其他一些答案.

原版的

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

//linuxserver/images/imagexxx.jpg
Run Code Online (Sandbox Code Playgroud)

那么也许你可以快速设置一个网络服务器并将网址存储在数据库中(以及本地路径).虽然数据库可以处理LOB和3000个图像(4-6百万像素,假设500K图像)1.5 Gigs并不是很多空间文件系统设计用于存储大型文件而不是数据库.

  • 但是你必须想出一种方法来将文件分布在几个目录中.文件系统并不擅长在*single*目录中存储数百万个文件(实际上已有数千个文件存在问题) (13认同)

Jan*_*ena 10

2022答案

现在最常见的模式是仅在数据库中存储对图像的引用,并将图像本身存储在文件系统(即 S3 存储桶)中。

好处是您的数据库备份更小,不再存在单点故障,现在可以将负载分散到数据库之外,并且云存储桶通常比数据库存储更便宜。

缺点是您必须在两个位置管理图像 - 删除一个图像,您的应用程序需要跟踪并从另一个位置删除它。

  • 请问为什么不再出现单点故障了?您的解决方案仍然需要数据库,并且您还需要 S3 存储,那么是否会出现更多的故障点呢? (2认同)
  • 但是如果 S3 或数据库无法工作,你的服务就无法工作,所以不,我们的单点故障并没有减少,我确实意味着你多了一个单点故障。数据恢复发生在故障之后,并不意味着没有发生故障 (2认同)

Mik*_*ell 6

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


ccl*_*eve 5

如果您的图像很小,请考虑将它们以 base64 格式存储在纯文本字段中。

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

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

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

(OP的图像不小,所以这不是他问题的真正答案。)