【问题标题】:Storing Images in PostgreSQL在 PostgreSQL 中存储图像
【发布时间】:2010-09-08 10:39:18
【问题描述】:

好的,所以我正在开发一个应用程序,该应用程序将使用运行 PostgreSQL 的 Linux 后端向 Windows 机器提供图像,前端是用 C#.NET 编写的,尽管前端应该无关紧要。我的问题是:

  • 在 Postgres 中存储图像的最佳方式是什么?

每个图像大约 4-6 兆像素,我们存储的图像超过 3000 个。还需要注意的是:这不是一个 Web 应用程序,最多有大约两个前端访问数据库一次。

【问题讨论】:

    标签: postgresql image


    【解决方案1】:

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

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

    过去,我使用 bytea 列非常成功地存储了 10+gb 和数千行的图像。 PG 的 TOAST 功能几乎否定了 blob 的任何优势。无论哪种情况,您都需要为文件名、内容类型、尺寸等包含元数据列。

    【讨论】:

    • 10GB 并不多 :-( 我正在寻找 TBs 解决方案
    • @ValentinHeinitz 对于 TB,普通 Postgres 甚至在文本列较小的情况下也会遇到困难。
    【解决方案2】:

    试试this。我使用大对象二进制 (LOB) 格式将生成的 PDF 文档存储在数据库中,其中一些文件大小超过 10 MB,而且效果非常好。

    【讨论】:

      【解决方案3】:

      10 年后更新 在 2008 年,与存储文件的磁盘相比,您将运行数据库的硬盘具有许多不同的特性和更高的成本。现在有更好的解决方案来存储 10 年前不存在的文件,我会撤销此建议并建议读者查看此线程中的其他一些答案。

      原创

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

      //linuxserver/images/imagexxx.jpg
      

      那么也许您可以快速设置网络服务器并将网络 URL 存储在数据库中(以及本地路径)。虽然数据库可以处理 LOB 和 3000 张图像(4-6 兆像素,假设 500K 图像),但 1.5 Gigs 的空间并不多,文件系统比数据库更适合存储大文件。

      【讨论】:

      • 但是您必须想出一种方法来将文件分布在多个目录中。文件系统不太擅长将数百万个文件存储在一个单个目录中(实际上一万个已经是个问题了)
      • 不回答原始问题。我个人希望将图像存储在 Postgres 中,只是因为我希望 SQL 作为我的抽象层,并且不想管理我的 ext4 文件系统中的文件。
      • 我很矛盾,这不能回答问题,但我赞成,因为它比问题的答案更好。
      【解决方案4】:

      Re jcoby 的回答:

      bytea 是一个“普通”列也意味着当你获取它时该值被完全读入内存。相比之下,Blob 可以流式传输到标准输出。这有助于减少服务器内存占用。尤其是当您存储 4-6 个 MPix 图像时。

      备份 blob 没问题。 pg_dump 提供“-b”选项来将大对象包含到备份中。

      所以,我更喜欢使用 pg_lo_*,你可能猜到了。

      关于克里斯·埃里克森的回答:

      我会说相反的:)。当图像不是您存储的唯一数据时,除非绝对必要,否则不要将它们存储在文件系统上。始终确保您的数据一致性并将数据“整合”(数据库)是非常有好处的。顺便说一句,PostgreSQL 在保持一致性方面非常出色。

      但是,确实,现实通常对性能要求太高 ;-),它促使您从文件系统中提供二进制文件。但即便如此,我还是倾向于将数据库用作二进制文件的“主”存储,所有其他关系始终链接在一起,同时提供一些基于文件系统的缓存机制来优化性能。

      【讨论】:

      • 10年后,你认为你的积分还有效吗?从那以后有什么更新吗?
      • @leventunver 不,不要持有的积分。例如,第一个关于 BYTEA 是“正常”列。 Postgres 多年来一直支持 streaming 到/来自BYTEA 列,这意味着您不必在将内容存储到数据库之前将其存储在内存中。
      【解决方案5】:

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

      我们需要区分“原始图像”和“处理后的图像”,例如缩略图。

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

      • 使用blob(二进制大对象):用于原始图像存储,在您的餐桌上。请参阅 Ivan 的回答(备份 blob 没问题!)、PostgreSQL additional supplied modulesHow-tos 等。

      • 使用带有DBlink 的单独数据库:用于原始图像存储,在另一个(统一/专用)数据库中。在这种情况下,我更喜欢 bytea,但 blob 几乎相同。分离数据库是“统一图像Web服务”的最佳方式。

      • 使用 bytea (BYTE Array):用于缓存缩略图。缓存小图像以将其快速发送到网络浏览器(以避免呈现问题)并减少服务器处理。缓存也是必不可少的元数据,例如宽度和高度。数据库缓存是最简单的方法,但请检查您的需求和服务器配置(例如 Apache 模块):store thumbnails at file system 可能会更好,比较性能。请记住,它是一个(统一的)Web 服务,然后可以存储在一个单独的数据库中(没有备份),为许多表提供服务。另见PostgreSQL binary data types manualtests with bytea column等。

      注意1:今天不推荐使用"dual solutions" (database+filesystem) (!)。使用“仅数据库”而不是双重的有很多优点。 PostgreSQL 在导出/导入/输入/输出方面具有相当的性能和良好的工具。

      NOTE2:记住PostgreSQL只有bytea,没有默认Oracle的BLOB:“SQL标准定义(...)BLOB。输入格式不同来自 bytea,但提供的函数和运算符基本相同",Manual.


      编辑 2014:我今天没有更改上面的原文(我的回答是 2012 年 4 月 22 日,现在有 14 票),我正在为您的更改打开答案 em>(参见“Wiki 模式”,您可以编辑!),用于proofreading用于更新
      这个问题很稳定(@Ivans 08 年的回答有 19 票),请帮助改进这篇文章。

      【讨论】:

      【解决方案6】:

      快速更新至 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,而实际文件系统上仍然存在,这意味着您可以使用任何您想要的文件系统并且网络服务器可以提供服务直接使用它们(操作系统缓存也适用)。

      【讨论】:

      • 谢谢.. 外部数据包装器 (file_fdw) 是否为图像提供写访问权限?我想将图像存储到文件系统及其在 Postgresql 中的元数据,但我也必须保持一致性。你有详细的解决方案吗?有没有其他可用的扩展程序? Multicorn 需要 python,我宁愿不用 Python 也能做到。
      • 是的,他们有写权限。它们在两个方向上都是完全一致的。不,我不知道没有 python 的同等解决方案。
      【解决方案7】:

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

      原因是,虽然 base64 的开销为 33%,但压缩大部分消失了。 (参见What is the space overhead of Base64 encoding?)您的数据库会更大,但您的网络服务器发送给客户端的数据包不会更大。在 html 中,您可以在 标记中内联 base64,这可能会简化您的应用程序,因为您不必在单独的浏览器获取中将图像作为二进制文件提供。当您必须发送/接收 json 时,将图像作为文本处理也可以简化事情,这不能很好地处理二进制。

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

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

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

      【讨论】:

        猜你喜欢
        • 2015-07-01
        • 2021-04-30
        • 2019-04-09
        • 2016-08-04
        • 2022-01-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-11
        相关资源
        最近更新 更多