好的,我正在开发一个应用程序,它将使用运行PostgreSQL的Linux后端向一个Windows框架提供图像服务,而前端是用C#.NET编写的,尽管前端几乎不重要。我的问题是:
- 在Postgres中存储图像的最佳方法是什么?
这些图像每个大约有4-6百万像素,并且我们正在存储超过3000张图片。另外需要注意的是:这不是一个Web应用程序,最多只会有两个前端同时访问数据库。
好的,我正在开发一个应用程序,它将使用运行PostgreSQL的Linux后端向一个Windows框架提供图像服务,而前端是用C#.NET编写的,尽管前端几乎不重要。我的问题是:
这些图像每个大约有4-6百万像素,并且我们正在存储超过3000张图片。另外需要注意的是:这不是一个Web应用程序,最多只会有两个前端同时访问数据库。
更新到2012年,当我们看到图片尺寸和数量在所有应用程序中不断增长时...
我们需要一些区分“原始图像”和“处理后的图像”,例如缩略图。
正如Jcoby的回答所说,那么有两个选项,我建议:
使用blob (二进制大型对象): 用于原始图像存储,存储在您的表中。请参见伊万的答案(不会出现备份blob的问题!),PostgreSQL附加提供的模块,How-tos等。
使用单独的数据库和DBlink:用于原始图像存储,在另一个(统一/专业)数据库中。在这种情况下,我更喜欢使用bytea,但blob几乎相同。分离数据库是“统一图像网络服务”的最佳方式。
使用bytea(BYTE Array):用于缓存缩略图像。将小图像缓存以快速发送到Web浏览器(避免渲染问题)并减少服务器处理。缓存还包括必要的元数据,如宽度和高度。数据库缓存是最简单的方法,但请检查您的需求和服务器配置(例如Apache模块):store thumbnails at file system可能更好,比较性能。请记住,它是一个(统一的)Web服务,可以存储在单独的数据库中(没有备份),为多个表提供服务。请参阅PostgreSQL二进制数据类型手册,tests with bytea column等。
注意1:今天使用“双重解决方案”(数据库+文件系统)已经被弃用。使用“仅数据库”而不是双重解决方案有许多优点。PostgreSQL具有可比较的性能和良好的导出/导入/输入/输出工具。
注意2:请记住,PostgreSQL仅有bytea,没有默认的Oracle的BLOB:“SQL标准定义了……BLOB。输入格式与bytea不同,但提供的函数和运算符大多相同”,手册。
编辑2014年:我今天没有更改上面的原始文本(我的答案是Apr 22'12,现在有14票),我开放答案供您更改(请参阅“Wiki模式”,您可以进行编辑!)proofreading和更新。
问题很稳定(@Ivans的'08答案获得19票),请帮助改进此文本。
关于jcoby的回答:
bytea作为“普通”列意味着在提取它时,该值会完全读入内存。相反,对于blob,您可以将其流式传输到标准输出。这有助于减少服务器内存占用。特别是当你存储4-6 MPix图像时。
备份blob没有问题。pg_dump提供“-b”选项将大型对象包含在备份中。
因此,我更喜欢使用pg_lo_ *,你也许可以猜到。
关于Kris Erickson的回答:
我会说相反的观点:)。当图像不是您存储的唯一数据时,请不要存储它们在文件系统中,除非您绝对必须这样做。始终确保数据一致性是一个巨大的好处,并且使数据“完整”(数据库)。顺便说一下,PostgreSQL在保持一致性方面非常出色。
然而,现实往往对性能要求过高,迫使您从文件系统中提供二进制文件。但即使如此,我也倾向于将数据库用作二进制文件的“主”存储,所有其他关系都保持一致,并提供一些基于文件系统的缓存机制以进行性能优化。
BYTEA
是一个“常规”列的说法。多年来,Postgres 已支持对/从 BYTEA
列进行流式传输,这意味着在将其存储到数据库中之前,您不必将内容存储在内存中。 - oligofren在数据库中,有两种选项:
我过去曾经非常成功地使用bytea列来存储10多GB的图像并包含数千行。PG的TOAST功能基本上抵消了blobs所具有的任何优势。您需要在任一情况下都包含元数据列,例如文件名、内容类型、尺寸等。
2015年中期的快速更新:
您可以使用Postgres Foreign Data interface将文件存储在更适合的数据库中。例如,将文件放入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服务器可以直接提供它们(OS缓存也适用)。
10年后的更新 在2008年,用于运行数据库的硬盘具有与存储文件的磁盘非常不同的特征和更高的成本。现如今,有比10年前更好的存储文件的解决方案,我会撤回这个建议并建议读者查看该主题中的其他答案。
原始内容
除非你确实必须这样做,否则不要将图像存储在数据库中。虽然我明白这不是一个Web应用程序,但如果没有共享的文件位置可以指向,在数据库中保存文件的位置就没有意义。
//linuxserver/images/imagexxx.jpg
如果您可以快速设置Web服务器并将Web网址以及本地路径存储在数据库中(以及本地路径),那么也许您可以这样做。 虽然数据库可以处理LOB和3000个图像(4-6百万像素,假设每个图像500K),但1.5 GB的空间不算很多,文件系统比数据库更适合存储大型文件。
2022年答案
现在最常见的模式是仅在数据库中存储图像的引用,并将图像本身存储在文件系统中(即S3桶)。
好处是,您的数据库备份更小,不再存在单点故障,负载现在可以分散到远离数据库的地方,而且云存储桶通常比数据库存储更便宜。
不利之处是,您必须在两个位置管理图像 - 删除一个图像后,您的应用程序需要跟踪并从另一个位置删除它。