将图像单独存储在数据库中通常不是一个好主意
查看is it better to store images in a BLOB or just the URL? 和Files - in the database or not? 上的讨论。请注意,这些问题及其答案与 PostgreSQL 无关。
这有一些 PostgreSQL 特定的问题。 PostgreSQL 没有任何增量转储工具*,因此如果您使用pg_dump 备份,则必须为每个备份转储所有图像数据。存储空间和传输时间可能是一个问题,尤其是因为您应该保留数周的备份,而不仅仅是一个最近的备份。
如果图像很大或很多,您可能需要考虑将图像存储在文件系统中,除非您强烈需要对它们进行事务性、符合 ACID 的访问。将文件名存储在数据库中,或者只是根据有用的密钥建立文件命名约定。这样您就可以轻松地对图像目录进行增量备份,将其单独管理到适当的数据库中。
如果您将图像存储在 FS 中,您将无法通过 PostgreSQL 数据库连接轻松† 访问它们。 OTOH,您可以直接通过 HTTP 直接从文件系统为它们提供服务,这比您必须首先从数据库查询它们时曾经希望的效率要高得多。如果您的图像在 FS 上,但不是来自数据库,则特别是 can use sendfile() from rails。
如果你真的必须将图像存储在数据库中
...那么它在概念上与 .NET 中的相同,但具体细节取决于您使用的 Pg 驱动程序,您没有指定。
有两种方法:
- 按照您的要求存储和检索
bytea;和
- 使用内置的大对象支持,这通常比使用
bytea 更可取。
对于可以使用 bytea 的小图像:
- 将图像数据从客户端读取到局部变量中
- 通过将变量作为 bytea 传递将其插入 DB。假设您使用的是
ruby-pg 驱动程序,那么驱动程序中的 test_binary_values 示例应该会对您有所帮助。
对于更大的图像(超过几兆字节),请改用 lo:
对于更大的图像,请不要使用bytea。理论上最大可能是 2GB,但是in practice you need 3x the RAM (or more) as the image size would suggest 所以你应该避免使用bytea 来处理大图像或其他大的二进制数据。
PostgreSQL 为此有一个dedicated lo (large object) type。仅在 9.1 上:
CREATE EXTENSION lo;
CREATE TABLE some_images(id serial primary key, lo image_data not null);
...然后使用lo_import 从磁盘上的临时文件中读取数据,因此您不必一次将整个文件放入 RAM。
驱动程序ruby-pg 为lo_create、lo_open 等提供wrapper calls,并为本地文件访问提供lo_import。见this useful example。
请使用大对象而不是bytea。
* 增量备份可以通过流复制、PITR / WAL 归档等进行,但再次增加数据库大小会使 WAL 管理等事情变得复杂。无论如何,除非您是专家(或“勇敢”),否则您应该使用pg_dump 备份,而不是仅依赖复制和 PITR。将图像放入数据库也会 - 通过增加数据库的大小 - 大大减慢 pg_basebackup,这在故障转移场景中可能很重要。
†adminpack 通过 Pg 连接为超级用户提供本地文件访问。不过,您的 webapp 用户应该从不拥有超级用户权限,甚至应该拥有它所使用的表的所有权。通过WebDAV 等单独的安全通道读取和写入文件。