代码之家  ›  专栏  ›  技术社区  ›  akdom

在PostgreSQL中存储图像

  •  86
  • akdom  · 技术社区  · 17 年前

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

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

    每幅图像大约有400-600万像素,我们存储的图像超过3000个。注意:这不是一个web应用程序,最多有两个前端同时访问数据库。

    6 回复  |  直到 17 年前
        1
  •  54
  •   Peter Krauss    6 年前

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

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

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

    • 使用 团块 (二进制大对象):用于原始图像存储,在表中。看看伊万的答案(备份blob没问题!), PostgreSQL additional supplied modules , How-tos 等。

    • 使用单独的数据库 DBlink :对于原始图像存储,位于另一个(统一/专用)数据库。在这种情况下,我更喜欢 二进制数据 ,但是 团块 几乎是一样的。分离数据库是“统一图像web服务”的最佳方式。

    • 使用 二进制数据 (字节数组):用于缓存缩略图。缓存小图像以将其快速发送到web浏览器(以避免渲染问题)并减少服务器处理。缓存还包括重要的元数据,如宽度和高度。数据库缓存是最简单的方法,但请检查您的需要和服务器配置(例如,Apache模块): store thumbnails at file system 可能更好,比较一下表现。请记住,它是一个(统一的)web服务,然后可以存储在一个单独的数据库(无备份)中,为许多表提供服务。另见 PostgreSQL binary data types manual , tests with bytea column 等等。

    注1:今天使用 "dual solutions" (database+filesystem) 已弃用(!)。使用“仅数据库”而不是“双数据库”有许多优点。PostgreSQL具有可比的性能和良好的导出/导入/输入/输出工具。

    注意2:记住PostgreSQL只有 二进制数据 ,没有默认的Oracle 团块 :“SQL标准定义(…)BLOB。输入格式与bytea不同,但提供的函数和运算符基本相同“, Manual .


    编辑 二千零一十四 :我今天没有修改上面的原文(我的答案是4月22日12日,现在有14票), 我为你的改变打开了答案 (请参阅“Wiki模式”,您可以编辑!),用于 proofreading 用于更新 .
    问题是稳定的(@Ivans'08的答案是19票),请帮助改进这篇文章。

        2
  •  52
  •   Ivan Krechetov    17 年前

    关于jcoby的回答:

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

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

    所以,我更喜欢用pg_lo_u*,你可以猜。

    Re-Kris Erickson的回答:

    我会说相反的话:)。当图像不是您存储的唯一数据时,不要将它们存储在文件系统中,除非您必须这样做。总是确保数据的一致性,并将数据“放在一块”(DB)中,这是一个很大的好处。顺便说一下,PostgreSQL在保持一致性方面非常出色。

    然而,事实上,现实常常对性能要求太高;-),它会迫使您从文件系统中提供二进制文件。但即便如此,我还是倾向于使用DB作为二进制文件的“主”存储,所有其他关系都保持一致的链接,同时提供一些基于文件系统的缓存机制以优化性能。

        3
  •  26
  •   jcoby    17 年前

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

    • 再见。将数据存储在列中,作为备份的一部分导出。使用标准数据库函数来保存和检索。为您的需要推荐。
    • 布洛布。存储外部数据,通常不作为备份的一部分导出。需要特殊的数据库函数来保存和检索。

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

        4
  •  21
  •   Innokentiy Alaytsev Hulor    8 年前

    快速更新至2015年年中:

    你可以使用 Postgres外部数据接口 ,以将文件存储在更合适的数据库中。例如,将文件放在GridFS中,GridFS是MongoDB的一部分。然后使用 https://github.com/EnterpriseDB/mongo_fdw 在Postgres中访问它。

    这有优势,你可以访问/读/写/备份它在Postrgres和MunGDB,这取决于什么给你更多的灵活性。

    还有用于文件系统的外部数据包装器: https://wiki.postgresql.org/wiki/Foreign_data_wrappers#File_Wrappers

    作为一个例子,您可以使用这个: https://multicorn.readthedocs.org/en/latest/foreign-data-wrappers/fsfdw.html (请参阅此处以获取简短的用法示例)

    这使您具有一致性(所有链接的文件都肯定存在)和所有其他acid的优势,而实际的文件系统上仍然存在这些acid,这意味着您可以使用任何想要的文件系统,并且web服务器可以直接为它们提供服务(操作系统缓存也适用)。

        5
  •  17
  •   Kris Erickson    7 年前

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

    原件

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

    //linuxserver/images/imagexxx.jpg
    

    然后,也许您可以快速设置一个web服务器并将web url存储在数据库中(以及本地路径)。虽然数据库可以处理LOB和3000个图像(400-600万像素,假设一个图像有500万像素),但1.5gigs并不是很多空间文件系统比数据库更适合存储大文件。

        6
  •  6
  •   Mike Reedell    17 年前

    尝试 this . 我使用大对象二进制(LOB)格式将生成的PDF文档(其中一些文档大小为10+MB)存储在数据库中,它工作得非常好。

        7
  •  0
  •   ccleve    6 年前

    如果图像很小,请考虑将其作为base64存储在纯文本字段中。

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

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

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

    (OP的图片不小,所以这并不是对他的问题的回答。)