好吧,我正在开发一个应用程序,它将使用一个运行 PostgreSQL 的 Linux 后端,将图像提供给一个前端使用 C # .NET 编写的 Windows 机器,尽管前端应该没什么关系。我的问题是:
每张图像大约有400-600万像素,我们存储了3000多张。同样值得注意的是: 这不是一个 web 应用程序,最多只有两个前端同时访问数据库。
在数据库中,有两个选项:
我曾经成功地使用 bytea 列来存储10 + gb 的图像,其中有数千行。PG 的 TOAST 功能几乎否定了 blobs 所具有的任何优势。无论是文件名、内容类型还是维度,都需要包含元数据列。
10年后更新 在2008年,运行数据库的硬盘驱动器的特性将大不相同,成本也比存储文件的磁盘高得多。如今,存储10年前不存在的文件有了更好的解决方案,我要撤销这个建议,并建议读者看看这个帖子中的其他一些答案。
原创的
除非万不得已,否则不要在数据库中存储图像。我知道这不是一个网络应用程序,但如果没有共享文件位置,你可以指向保存在数据库中的文件位置。
//linuxserver/images/imagexxx.jpg
然后,也许你可以快速设置一个网络服务器和存储在数据库中的网址(以及本地路径)。虽然数据库可以处理 LOB 和3000个图像(4-6百万像素,假设每个图像50万)1.5吉格并不是很多空间文件系统比数据库更适合存储大文件。
对于 jcoby 的回答:
Bytea 是一个“正常”列,也意味着当您获取它时,该值将被完全读入内存。相反,Blob 可以流入 stdout。这有助于减少服务器内存占用。特别是,当您存储4-6 MPix 图像。
备份 blobs 没有问题。 pg _ dump 提供了“-b”选项,可以将大型对象包含到备份中。
因此,您可能会猜测,我更喜欢使用 pg _ lo _ * 。
克里斯•埃里克森(Kris Erickson)的回答:
我要说的恰恰相反:)。当图像不是您存储的唯一数据时,除非万不得已,否则不要将它们存储在文件系统中。始终确保数据的一致性,并使数据“完整”(数据库) ,这是非常有益的。顺便说一句,PostgreSQL 在保持一致性方面非常出色。
然而,事实上,现实往往对性能要求太高; ——) ,它迫使您从文件系统中提供二进制文件。但即便如此,我还是倾向于使用 DB 作为二进制文件的“主”存储,所有其他关系一致链接,同时为性能优化提供一些基于文件系统的缓存机制。
更新到2012年,当我们看到图像的大小和数量,正在增长和增长,在所有的应用..。
我们需要区分“原始图像”和“处理过的图像”,比如缩略图。
正如 Jcoby 的回答所说,有两种选择,那么,我建议:
使用 一团(二进位大型物件) : 原始图像存储,在您的表。看看 Ivan 的回答(备份 blob 没有问题!)PostgreSQL 附加提供的模块、 怎么做等。
使用单独的数据库与 闪烁: 原始图像存储,在另一个(统一/专门)数据库。在这种情况下,我更喜欢 Bytea,但是 一团接近相同。分离数据库是实现“统一图像网络服务”的最佳途径。
使用 Bytea(BYTE 数组) : 缓存缩略图。缓存这些小图片以便快速发送到 Web 浏览器(以避免呈现问题)并减少服务器处理。还缓存必要的元数据,如宽度和高度。数据库缓存是最简单的方法,但请检查您的需求和服务器配置(例如。Apache 模块) : 在文件系统中存储缩略图可能更好,比较性能。请记住,它是一个(统一的) Web 服务,然后可以存储在一个单独的数据库中(不需要备份) ,服务于多个表。参见 PostgreSQL 二进制数据类型手册,用茶叶柱进行试验等。
注1: 今天不推荐使用 “双重解决方案”(数据库 + 文件系统)(!).“只使用数据库”而不使用双重数据库有许多优点。PostgreSQL 在导出/导入/输入/输出方面具有可比性能和良好的工具。
注意2: 记住 PostgreSQL 只有 Bytea,没有默认的 Oracle 的 一团: “ SQL 标准定义(...) BLOB。输入格式与 bytea 不同,但提供的函数和操作符大体相同”,手册。
编辑 二零一四年: 我今天没有改变上面的原文(我的答案是4月22’12,现在有14票) ,我正在为你的改变打开答案(见“ Wiki 模式”,你可以编辑!)对于 校对和 更新资料。< br/> 问题是稳定的(@Ivan’08的回答有19票) ,请帮助改进这篇文章。
快速更新到2015年中期:
您可以使用 Postgres 外部数据接口,将文件存储在更合适的数据库中。例如,将文件放在属于 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,而实际的文件系统仍然有,这意味着你可以使用任何你想要的文件系统,网络服务器可以直接为他们服务(操作系统缓存也适用)。
如果您的图像很小,可以考虑将它们以 base64的形式存储在纯文本字段中。
原因是 base64的开销为33% ,而压缩大部分都消失了。(见 Base64编码的空间开销是多少?)您的数据库将更大,但数据包您的网络服务器发送到客户端将不会。在 html 中,您可以在 < img src = “””> 标记中内联 base64,这可能会简化您的应用程序,因为您不必在单独的浏览器提取中以二进制形式提供图像。将图像作为文本处理还可以简化必须发送/接收 json 时的事情,json 不能很好地处理二进制文件。
是的,我理解您可以将二进制文件存储在数据库中,并在进出数据库的过程中将其转换为/从文本转换,但有时 ORM 会让这变得很麻烦。把它当作直接的文本来处理可能更简单,就像处理所有其他字段一样。
这绝对是处理缩略图的正确方法。
(OP 的图片并不小,所以这并不是他问题的答案。)
2022答案
现在最常见的模式是只在数据库中存储对图像的引用,并将图像本身存储在文件系统中(即 S3 bucket)。
这样做的好处是数据库备份更小,不再有单点故障,现在可以将负载从数据库分配出去,而且云存储存储桶通常比数据库存储更便宜。
不好的方面是,你必须在两个位置管理图像——删除一个图像,你的应用程序需要跟踪并从另一个位置删除它。