【问题标题】:Would you store binary data in database or in file system? [closed]您会将二进制数据存储在数据库中还是文件系统中? [关闭]
【发布时间】:2010-10-14 07:58:17
【问题描述】:

这是一个以前曾被问过的问题 (large-text-and-images-in-sql),但主要是针对将要更改的数据。在我的情况下,数据将被存储并且永远不会改变。将所有东西放在一起似乎是明智的。

有什么理由不应该将静态二进制数据存储在数据库中?

假设这是一件明智的事情,将这些数据存储在单独的表中是否有什么好处? (你现在可能开始意识到我不是数据库专家......)

澄清: 可能不会超过 10-20 个用户,但这些用户将在美国和英国。在任何情况下都必须传输二进制数据。

【问题讨论】:

    标签: database binary-data


    【解决方案1】:

    将数据存储在数据库中的优势在于利用数据库安全机制并降低维护成本(备份、...)。它的缺点是增加了数据库负载和消耗连接(这对于每个连接许可的数据库服务器可能很昂贵)。如果您使用的是 SQL Server 2008,FILESTREAM 可能是一个不错的选择。

    顺便说一句,对于 Web 应用程序(或任何其他可能需要流式传输数据的应用程序),将数据存储在 DB 之外通常更明智。

    【讨论】:

    • 我不确定它如何降低维护/备份成本。如果有的话,它会增加它们,因为通常备份数据库比备份文件系统更昂贵且要求更高。你能详细说明一下吗?
    • @jrwren 我的意思是您不需要单独备份文件并手动保持它们同步以确保数据库备份中包含的数据的完整性。它可以根据情况以一种或另一种方式更直接和更便宜。
    【解决方案2】:

    当表中包含 LOB 时,所有这些关于执行“从表中选择 *”导致巨大内存和/或带宽问题的讨论都不是问题。返回的只是一个指向相关 LOB 的指针。没有足够的声誉将评论放在上下文中,但看到这个的人应该知道这不是问题。

    【讨论】:

    • @Matthew 我想他的意思是Large OBject
    • 如果您使用 ORM,ORM 可能会提取所有二进制数据。例如,EF 会要求您将 blob 保存在一个单独的延迟加载的表中,或者只提取您需要的列(这在 EF 中有点笨拙)。
    【解决方案3】:

    存储 BLOBS 的最大缺点是内存消耗。 你能想象 select * from x 会对每条 45k 图像的数千条记录做什么吗?

    正如 Mehrdad 所说,也有优势。因此,如果您决定采用这种方法,您应该尝试设计您的数据库,以便大多数查询返回较少的结果,其中包含 BLOB 数据。例如,可能为此目的建立一对一的关系。

    【讨论】:

    • +1 好点 - 也许是把 blob 放在单独的表中并通过 id 提取的好理由?
    • 说实话我一直害怕使用 BLOB,因为我对 sql 很烂。但是,如果必须,我可能会为每个 blob 建立单独的一对一关系。几乎使用它,因为我使用对文件的引用。除了这些将存储在数据库中。注意:请不要在 webapps 中这样做。
    • 恕我直言,这不是一个有效的论点。在大多数情况下,使用select * from x 是一个坏主意,除非您需要在应用程序中使用表格的每个 列。将 blob 放在单独的表中更糟糕,因为它需要连接并使请求复杂化。
    • @Arseni Mourzenko:恕我直言,将 BLOBS 放在单独的一对一表中不会显着“使请求复杂化”相对于规范。大多数重要的数据库(即使没有 BLOBS)都有很多子表,即使对于简单的 CRUD 操作也需要加入,更不用说这些表通常是一对多的。此外,对于不涉及 BLOBS 的请求(这很常见,即仅获取搜索结果网格的元数据),将 BLOBS 放在单独的表中可以显着减少数据页的数量数据库服务器必须通读。
    【解决方案4】:

    我熟悉一个规模相当大的 OSS 项目,该项目一开始就决定将图像存储在 MySQL 数据库中,事实证明,它是他们一直在应对的三大坏主意之一。 (“无情地重构”是一种诅咒,但这是另一回事。)

    这导致的严重问题包括:

    1. 超过最大有效数据库大小 (mysql)。 (图像所需的总空间至少比其他所有空间高 2 个数量级)。

    2. 图像文件失去其“文件性”。除非存储(冗余)为日期(需要代码进行管理),否则没有日期大小等。

    3. 对于存储或操作而言,任意字节序列并非始终都能很好地处理。

    4. “我们永远不需要从外部访问图像”是一个危险的假设。

    5. 脆弱。因为整个安排是不自然的和敏感的,你不知道它接下来会咬到哪里(助长了反重构的心态)。

    好处?没有我能想到的,除了它可能是当时阻力最小的路径。

    【讨论】:

    • 我假设错误的决定是存储 blob。对吗?
    • 一个重要的好处是数据的一致性:如果没有元数据,则无法删除“文件”,反之亦然。对于磁盘文件没有这样的限制,添加/删除文件及其元数据是必须设计、实现和使用的单独应用程序(或功能)。
    • 是的,您仍然需要编写一个经过适当验证的应用程序 - 但无论哪种方式都是如此。我不会将差异称为“实质性”。 重要的是,当其他应用程序和实用程序只能通过数据库调用获得图像时,需要额外的工作才能获得这些图像,并且大多数图像处理软件都没有内置数据库持久性. 因此,要查看图像,需要使用一个应用程序将其提取,然后使用另一个应用程序查看,然后确保在完成后将其放回正确的位置。比如说,忘记在资源管理器中浏览图片。
    【解决方案5】:

    从原则的角度解决问题,关系数据库(主要)用于存储结构化数据。如果您无法在数据元素上创建查询条件或连接,则它可能不属于数据库。我没有看到 WHERE 子句中使用了图像 BLOB,所以我会说将其保留在数据库之外。另一方面,CLOB 可用于查询。

    【讨论】:

    • 我们可能也不会在 WHERE 子句中使用电话号码,因为通过电话号码搜索任何内容并不常见(除非您正在使用反向查找系统)。也就是说,我们确实将电话号码存储在数据库中,而不是外部文件中,即使它很少用作连接或过滤条件。我的意思是,这个原因不足以放弃将图像保存在关系数据库中的可能性。
    • 但是您可以对电话号码进行查询条件,或者将其用于连接,这是您无法对 BLOB 列合理执行的操作。
    【解决方案6】:

    我认为这取决于您的建筑的应用。如果您正在构建一个 CMS 系统,并且数据的用途是在 Web 浏览器中显示图像,那么将图像保存到磁盘而不是放入数据库中可能是有意义的。虽然老实说我会同时做这两件事,这可以允许将服务器添加到农场,而不必在整个地方复制文件。

    另一个用例可能是一个复杂的对象,例如工作流,甚至是具有大量相互依赖关系的业务对象。您可以将这两者序列化为二进制或基于文本的格式,并将它们保存在数据库中。然后,您将获得 DB 的好处:ATOMIC、备份等...

    我认为人们首先不应该使用select * 查询。您所做的是提供两种获取数据的方法,一种方法返回摘要信息,第二种方法将返回 blob。我无法想象为什么您需要一次返回数千张图像。

    【讨论】:

    • +1 对于这些想法。关于 select * from 部分。您不必手动编写该查询。一些 ORM 默认使用这种类型的查询,所以如果有人不小心……哎哟。
    • 嘿,你知道哪个 ORM 使用这些查询吗?我想远离他们。 nHibernate 我知道没有
    • 我在一些php框架中见过,不记得了。但由于他们是在一个网络应用程序中,他们可能认为 select * 是比 select foo, bar, sausage 少的数据。我敢打赌他们从来没有想过 BLOBS。
    • 或者关于select *的脆弱性...
    • 从 php 的角度来看,它看起来并不脆弱 :)。
    【解决方案7】:

    想在数据库中存储图像(或其他二进制文档)的人并不是我很满意的人。数据库用于存储 [主要是?] INDEXABLE、DISCRETE 数据。不是无意义的二进制数据的 BLOB。如果您曾亲身使用 BLOB 处理二进制数据,那么您已经知道这一点。

    您应该在文件系统中存储对该文件的引用。最佳实践是文件名,而不是绝对(甚至是相对)路径。

    【讨论】:

    • 就“SELECT *”而言,我认为在大多数情况下它是合理的。我构建了一个使用它的 ORM,但你可以覆盖它。如果你真的关心性能,你可以完全绕过 ORM 并使用 ORM 在幕后使用的查询构建器。关键是这个对话与“SELECT * ...”无关。它与健全的数据库设计有关。
    • 如果只存储文件名而不存储路径,如何检索文件?你会有一个文件夹来存放所有文件吗?如果我的数据库中有数百万个文件怎么办?
    • 在应用程序某处的配置中,您应该存储文件所在目录的路径。如果您担心同一目录中有太多文件,请动态构建路径。通常您可以为此使用 ID,例如 /path/to/files/{ID here}/filename.ext。您只需要存储文件名。
    【解决方案8】:

    我们将附件存储在我们的系统中,您无法更改附件,因此我认为我们在同一页面上包含“将被存储且永不更改”的数据。我们特别决定将其存储在数据库中。我们这样做有两个原因,简单性和备份/恢复时间。

    简单第一:在我们的例子中,这些附件是从最终用户的浏览器上传的,将它们写入目录(在数据库服务器上)比然后将它们流式传输到 SQL 管道更简单。数据库中有它们的记录,但数据库只包含有关附件的元信息,以及磁盘上文件的名称(在我们的例子中是一个 guid)

    在备份/恢复方面:这些 blob 可能会成为数据库中最大的部分之一。每当您运行完整备份时,您将一遍又一遍地复制这些位,即使您知道那时永远不会改变。对我们来说,拥有(很多)较小的备份似乎要简单得多,并将附件目录的 xcopy 复制到辅助服务器作为备份。

    【讨论】:

      【解决方案9】:

      这不正是 LOB 或 CLOB 或 .... 的设计目的吗?

      我们使用 CLOB 存储大型航空公司系统的信用卡交易的大量加密。

      不过,内存消耗是你最大的罪魁祸首。

      HTH

      干杯,

      【讨论】:

        【解决方案10】:

        某些数据库(例如 Postgresql)会自动压缩字段,直接从 db 读取字段可能会更快。而且,程序可以一举读取所有字段和图像。

        【讨论】:

        • 是的,如果我曾经使用过 blob,它会是 postgres。您节省带宽。但在某些时候,数据必须在应用程序的进程中解压缩。
        • 许多 blob(图像、mp3 等)基本上都是预压缩的。
        【解决方案11】:

        这里的性能问题已经在上面解决了,所以我不会重复它。但是我认为,如果您要存储大量流出的内容(例如网站上的图像/文档),那么构建缓存系统是一个很好的建议。

        我的意思是将所有数据存储在您的数据库中,但是当有人请求该文件时,请检查它是否存在于磁盘上(基于已知文件名,在临时文件夹中),如果不存在,则从数据库中获取它并将其写入文件夹,然后将其流式传输给用户。对于同一文件的下一个请求,由于它存在于磁盘上,因此可以从那里提供服务而无需访问数据库。但是,如果您需要删除这些文件(或者您的网络服务器崩溃了!),这并不重要,因为它们会在人们请求它们时从数据库中再次重建。这应该比从数据库中为同一文件的每个请求提供服务要快得多。

        【讨论】:

          猜你喜欢
          • 2010-10-20
          • 2011-01-05
          • 2014-02-11
          • 2014-02-25
          • 2011-10-06
          • 1970-01-01
          • 2011-10-19
          • 1970-01-01
          • 2012-08-29
          相关资源
          最近更新 更多