好的,所以我正在开发一个应用程序,该应用程序将使用运行 PostgreSQL 的 Linux 后端向 Windows 机器提供图像,前端用 C#.NET 编写,尽管前端几乎不重要。我的问题是:
- 处理在 Postgres 中存储图像的最佳方法是什么?
这些图像每个大约 4-6 兆像素,我们存储的图像超过 3000 个。还需要注意的是:这不是一个 Web 应用程序,最多有大约两个前端同时访问数据库。
好的,所以我正在开发一个应用程序,该应用程序将使用运行 PostgreSQL 的 Linux 后端向 Windows 机器提供图像,前端用 C#.NET 编写,尽管前端几乎不重要。我的问题是:
这些图像每个大约 4-6 兆像素,我们存储的图像超过 3000 个。还需要注意的是:这不是一个 Web 应用程序,最多有大约两个前端同时访问数据库。
更新到 2012 年,当我们看到图像大小和图像数量在所有应用程序中都在增长和增长时......
我们需要区分“原始图像”和“处理后的图像”,例如缩略图。
正如 Jcoby 的回答所说,我建议有两种选择:
使用blob (Binary Large OBject):用于原始图像存储,在您的餐桌上。请参阅 Ivan 的回答(备份 blob 没问题!)、PostgreSQL 附加提供的模块、操作方法等。
使用带有DBlink的单独数据库:对于原始图像存储,在另一个(统一/专业)数据库中。在这种情况下,我更喜欢bytea,但blob 几乎相同。分离数据库是“统一图像Web服务”的最佳方式。
使用bytea (BYTE Array):用于缓存缩略图。缓存小图像以将其快速发送到 Web 浏览器(以避免呈现问题)并减少服务器处理。缓存也是必不可少的元数据,例如宽度和高度。数据库缓存是最简单的方法,但请检查您的需求和服务器配置(例如 Apache 模块):将缩略图存储在文件系统中可能会更好,比较性能。请记住,它是一个(统一的)网络服务,然后可以存储在一个单独的数据库中(没有备份),为许多表提供服务。另请参阅PostgreSQL 二进制数据类型手册、使用 bytea 列的测试等。
注意1:今天不推荐使用“双重解决方案”(数据库+文件系统)(!)。使用“仅数据库”而不是双重的有很多优点。PostgreSQL 具有相当的性能和良好的导出/导入/输入/输出工具。
注意 2:请记住 PostgreSQL 只有bytea,没有默认 Oracle 的BLOB:“SQL 标准定义 (...) BLOB。输入格式与 bytea 不同,但提供的函数和运算符基本相同”,手册。
编辑2014:我今天没有更改上面的原文(我的回答是 2012 年 4 月 22 日,现在有 14 票),我正在为您的更改打开答案 (请参阅“Wiki 模式”,您可以编辑!),用于校对和更新。
问题是稳定的(@Ivans 的 08 年回答 19 票),请帮助改进此文本。
Re jcoby 的回答:
bytea 是一个“正常”列也意味着当您获取它时该值被完全读入内存。相比之下,Blob 可以流式传输到标准输出。这有助于减少服务器内存占用。特别是当您存储 4-6 个 MPix 图像时。
备份 blob 没问题。pg_dump 提供“-b”选项以将大对象包含到备份中。
所以,我更喜欢使用 pg_lo_*,你可能猜到了。
重新克里斯埃里克森的回答:
我会说相反的:)。当图像不是您存储的唯一数据时,除非绝对必须,否则不要将它们存储在文件系统上。始终确保您的数据一致性并将数据“整合”(数据库)是非常有好处的。顺便说一句,PostgreSQL 在保持一致性方面非常出色。
然而,确实,现实通常对性能要求太高了 ;-),它促使您从文件系统中提供二进制文件。但即便如此,我还是倾向于将数据库用作二进制文件的“主”存储,所有其他关系始终链接在一起,同时提供一些基于文件系统的缓存机制来优化性能。
在数据库中,有两个选项:
过去,我使用 bytea 列非常成功地存储了 10+gb 的数千行图像。PG 的 TOAST 功能几乎否定了 blob 的任何优势。无论哪种情况,您都需要为文件名、内容类型、尺寸等包含元数据列。
快速更新至 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,而实际文件系统上仍然存在,这意味着您可以使用任何您想要的文件系统并且网络服务器可以直接为它们提供服务(操作系统缓存也适用)。
10 年后的更新 在 2008 年,运行数据库的硬盘与存储文件的磁盘相比,具有不同的特性和更高的成本。现在有更好的解决方案来存储 10 年前不存在的文件,我会撤销这个建议并建议读者查看这个线程中的其他一些答案。
原来的
除非绝对必要,否则不要将图像存储在数据库中。我知道这不是一个 Web 应用程序,但如果没有共享文件位置,您可以指向将文件的位置保存在数据库中。
//linuxserver/images/imagexxx.jpg
那么也许您可以快速设置一个网络服务器并将网络 URL 存储在数据库中(以及本地路径)。虽然数据库可以处理 LOB 和 3000 张图像(4-6 兆像素,假设 500K 图像),但 1.5 Gigs 的空间并不多,文件系统比数据库更适合存储大文件。
试试这个。我使用大对象二进制 (LOB) 格式将生成的 PDF 文档存储在数据库中,其中一些文档的大小超过 10 MB,而且效果非常好。
如果您的图像很小,请考虑将它们以 base64 格式存储在纯文本字段中。
原因是虽然 base64 的开销为 33%,但压缩大部分消失了。(请参阅Base64 编码的空间开销是多少?)您的数据库会更大,但您的网络服务器发送给客户端的数据包不会更大。在 html 中,您可以在 <img src=""> 标记中内联 base64,这可能会简化您的应用程序,因为您不必在单独的浏览器获取中将图像作为二进制文件提供。当您必须发送/接收 json 时,将图像作为文本处理也可以简化事情,这不能很好地处理二进制文件。
是的,我知道您可以将二进制文件存储在数据库中,并在进出数据库的过程中将其转换为文本,但有时 ORM 会带来麻烦。像所有其他字段一样将其视为纯文本会更简单。
这绝对是处理缩略图的正确方法。
(OP的图像不小,所以这并不是他问题的真正答案。)