是否应将二进制文件存储在数据库中?


123

在数据库中存储与数据相关的二进制文件的最佳位置是什么?你应该:

  1. 用blob存储在数据库中
  2. 使用数据库中的链接存储在文件系统上
  3. 存储在文件系统中,但重命名为内容的哈希并将哈希存储在数据库中
  4. 我没想到的事

(1)的优点(尤其是)保留了事务的原子性。代价是您可能会大大增加存储(以及相关的流/备份)要求

(3)的目标是在某种程度上保留原子性-如果您可以强制执行写入操作,则不允许更改或删除文件,并且始终具有正确的哈希作为文件名。想法是在允许插入/更新引用哈希之前将文件写入文件系统-如果此事务在文件系统写入之后但在数据库DML之前失败,则可以,因为文件系统正在“伪造”为所有存储库可能的文件和哈希-里面是否有没有指向的文件都没关系(如果小心,可以定期清理它们)

编辑:

看起来有些RDBMS以各自的方式涵盖了这一点-我很想知道其他人是如何做到的-特别是在针对postgres的解决方案中


8
这个问题在这里重复:将图像存储在Blob或仅将URL中存储更好吗?由于这一点更加出色,因此对这一点予以关闭。请务必阅读两个问题以获得更多见解!
玛丽安

Answers:


57
  1. 用blob存储在数据库中

    缺点是它会使数据库文件变得很大,甚至可能太大而无法备份现有设置。优点是完整性和原子性。

  2. 使用数据库中的链接存储在文件系统上

    我遇到了如此可怕的灾难,令人恐惧的是,人们一直在建议这样做。一些灾难包括:

    • 一个特权用户将重新排列文件,并经常断开数据库中路径与它们现在所在位置之间的链接(但不知何故,这就是我的错)。
    • 从一台服务器移到另一台服务器时,某些文件的所有权丢失了,因为旧计算机的管理员帐户(运行旧网站的帐户)的SID不属于域,因此复制的文件具有可以访问的ACL无法解决,因此向用户显示用户名/密码/域登录提示。
    • C:\一路到所有路径,最终有些路径的长度超过256个字符,.doc并且并非所有版本的NT都能够处理长路径。
  3. 存储在文件系统中,但重命名为内容的哈希并将哈希存储在数据库中

    根据我对以上情况的解释,我最后工作的地方是这样做的。他们认为,这是组织无法获取大型数据库经验(规定大于40G的数据“太大”),公司无法购买大型硬盘驱动器以及无法购买更现代的后背之间的折衷方案。解决方案,以及摆脱我在上面确定的#1和#3风险的需要。

我的观点是,在多服务器方案中,尤其是在故障转移和可用性方面,以blob的形式存储在数据库中是一个更好的解决方案,并且具有更高的可伸缩性。


2
我不确定备份大小是否有问题;数据需要备份,但是要存储。无论是谈论FS还是DB,都会做出相同的差异与完全决定。我确实注意到这是一个可能的论点,而不是您的观点。
Phil Lello

2
我曾经遇到过一个问题,每天每行数千次写入数百兆字节。他们将GZIP文件作为10000个服务器的二进制文件存储在数据库中,但是引入了一个错误,即每个服务器在每个警报中记录每个服务器的信息。那太差了。在那件事之后,我坚决提出“除非有充分的理由,否则不要使用(最大)数据类型”。
阿里·拉泽吉

7
整个“链接断开”是一个应用程序问题,而不是数据库问题。数据库正在完成其工作(提供纯数据),而应用程序则没有(提供混合文件类型)。该应用程序应负责提供文件。通过将抽象路由路径存储在数据库中,无论文件内部存储在哪里,该抽象路由路径都将起作用(ala Symfony2路由)。这将抽象出本机路径,使应用程序更可移植,可维护,并允许切换到任何类型的文件系统而不会破坏任何内容。
Tek

29

编号1可实现完整的数据完整性。如果您不关心数据质量,请使用其他选项。就这么简单。

大多数RDBMS都有用于存储BLOB(例如SQL Server文件流)的优化。


(3)到底是什么使数据完整性面临风险?(假设您正确使用了交易API)
Jack Douglas

4
@JackPDouglas:您的哈希值不是正确的数据,并且仍然具有数据完整性的外部依赖关系
gbn

6
@JackPDouglas服务器管理员和DBA也有可能是不同的团队,并且存在文件被错误删除或未被备份的相关风险,因为它们被视为临时文件。
Phil Lello

21

如果要使用oracle,请查看dbfs和安全文件。

这说明了安全文件的全部内容,请确保所有数据在数据库中的安全。它以高大的形式组织。安全文件是lob的现代化版本,应将其激活。

dbfs是数据库中的文件系统。您可以像在网络主机上一样将其挂载在Linux主机上。它是真正强大的。查看博客它也有很多选项可以调整以满足您的特定需求。作为一个dba,给定一个文件系统(基于数据库,安装在Linux上),我在上面没有任何问题地创建了Oracle数据库。(数据库,存储在...数据库中)。并不是说这会很有用,但是它确实显示了力量。

更多优势包括:可用性,备份,恢复,所有读取均与其他关系数据一致。

有时会给出大小作为不将文档存储在数据库中的原因。可能必须以任何方式备份该数据,因此这不是不存储在数据库中的充分理由。特别是在旧文档被视为只读的情况下,很容易使数据库的大部分变为只读。在这种情况下,数据库的那些部分不再需要频繁备份。

表中对数据库外部内容的引用是不安全的。它可以被操纵,难以检查并且容易丢失。交易怎么样?该数据库为所有这些问题提供了解决方案。使用Oracle DBFS,您可以将您的文档提供给非数据库应用程序,他们甚至都不知道自己正在访问数据库。

最后一个大惊喜是,dbfs文件系统的性能通常比常规文件系统更好。如果文件大于几个块,则尤其如此。


15

我认为正确的答案在很大程度上取决于您的应用程序以及这些文档的重要性。

对于文档管理系统或对存储文档的可恢复性至关重要的系统(因此大多数事情与财务,HR或CRM相关),内联存储文档或使用您喜欢的DB供应商专有文档技术似乎是正确的做法。

但是,在许多应用程序中,我认为相反的决定是适当的。

服务台系统和wiki式系统的人,我觉得它使一个很大的意义,以保持数据数据库中。我相信有些人,例如Jira,实际上提供了选择是否要内联存储文档的选项。

对于中型企业,内联存储票务系统的文档可能意味着以MB为单位的压缩备份与以GB为单位的压缩备份之间的差异。

我个人更愿意在几分钟内使票务系统恢复在线状态,并与(通常不太重要的)文件费时几个小时来进行搏斗,而不是通过必须还原来增加我的“问题已破裂,CTO喘不过气来” RTO。并从更大的备份中重播日志。

将文档分开保存还有其他好处。

  • 您可以轻松地运行将文档元数据分类,执行病毒扫描,执行关键字索引编制等的单独过程。
  • 您可以利用工具来协助备份或恢复-rsync,存储快照等-与数据库相比,它们更适合于文件存储
  • 实际上,您可以使用支持压缩或重复数据删除的存储(SAN管理员多年来一直在忙碌的东西,也就是全世界数据库管理员的祸根)
  • 对于跨多个站点的安装,您可以使用分布式文件系统来补充集中式数据库

我认为#2和#3的混合组合可能很聪明。保留原始文件名,但计算并存储文档的哈希/校验和,以便您有一些参考点,以防他人移动或重命名文件时进行恢复。

使用原始文件名存储文件意味着应用程序可以从字面上直接从文件系统中提取文件并通过有线或在厚客户端环境中发送,甚至可以将用户直接指向文件服务器。


11

不要这样

在数据库中存储文件确实没有任何好处。

当您对自己进行思考时,它是否已经感到不可思议和可疑:

我应该将文件存储在数据库还是文件系统中

更好的是,大声说出来。

关于事实:

使用数据库

PROS ” ... 但不是很

  • 正确的“原子性”是一把双刃剑。因为它会拖累缺点。
  • 诚信 同上。

我真的不想被偏见,但我不认为有更多补充。如果您考虑一下的话,职业选手并不是真的很棒。

如果我忘了下面的评论,请同时阅读下面的内容。

缺点:

  • 工作工具错误
  • 难以维护
  • 忘记每位用户存储数百MB /千兆字节的数据了。
  • 备份快速增长的网站将是一场噩梦。
  • 恢复/移动也很烂。

使用文件系统

优点:

  • 更容易维护
  • 快速
  • 数据库备份与此无关
  • 可以说具有更高的便携性*

缺点

  • 没有*

*印刷精美

现在,您在问自己,等一下,这意味着没有缺点吗?怎么会?

这里最大的错误是人们试图用锤子拧螺丝。

最主要的原因是,我想说的唯一原因是文件链接

这是数据库无法解决的问题。如果您考虑一下,它甚至听起来很愚蠢。

“数据库将解决我的文件链接问题。”

实际上,从逻辑上讲,应用程序应实际上负责处理和提供链接。

一个解法:

  1. 使您的应用程序使用自定义路由处理URL请求。
  2. 将此路由保存到您的数据库。
  3. 在内部每次调用此路由时,将其映射到所需的文件。
  4. 如果您将文件移动到其他地方,只需更改路由的文件名值,该路由将始终为同一文件提供服务,无论它在网络上的存储或引用位置如何。

这还将抽象出本机路径,使应用程序更可移植,可维护,并允许切换到任何类型的文件系统而不会破坏任何内容。

至于如何实现它超出了此答案的范围,但是您可以看一看可以说是使用最广泛的Web语言(PHP)的一般示例:

https://github.com/symfony/路由

https://github.com/kriswallsmith/assetic

两者都非常强大。


1
您可能对此感兴趣:research.microsoft.com/apps/pubs/default.aspx? id=64525 Microsoft 进行的一项研究表明,在数据库中存储Blob实际上比在文件系统中存储Blob快(对于某些Blob大小)至少)。这与我的测试一致,该测试表明对于中等大小的Blob(<〜1MB),例如Postgres也比文件系统快。对于Oracle,它的性能大致相同,但是我尚未测试新的安全文件存储格式(但他们声称它比旧的存储格式快)
a_horse_with_no_name 2014年

我看到了,这就是为什么我谈论大文件的原因。另外,OP没有指定数据库供应商,因此供应商之间的性能可能有所不同,因此我的建议更为笼统。
Tek

9

我想在此添加有关折衷的经验。至少在PostgreSQL中,就数据库服务器而言,对性能的影响很小。大的Blob存储在单独的文件中,而不是存储在主堆表中,以便将它们移出可能占用大量记录的操作方式。其他数据库可能会执行类似的操作。

主要优点是能够将所有相关数据保留在一个地方,以实现原子性和备份目的。这大大减少了出现问题的机会。

主要的缺点不是我在上面看到的,这是前端的内存使用情况。我不确切地知道每个数据库是如何处理的,因此这可能取决于实现,但是对于PostgreSQL,数据以转义的ASCII字符串(可能是十六进制,可能是内联转义)的形式输入。然后必须在前端将其转换回二进制。我已经看到很多这样做的框架涉及传递值(不作为参考),然后基于该值构造一个新的二进制字符串。我计算出,使用Perl进行此操作最终要使用原始二进制文件要完成的内存的很多倍。

结论:如果仅偶尔访问文件,我将存储在数据库中。如果至少是在PostgreSQL中频繁且反复地访问它们,我认为成本会超过收益。


7

过去,Microsoft大力宣传了在数据库中存储图像(以及类似的Blob数据类型)的功能。这是SQL Server 2000的一个很酷的新功能(我很确定它是2000,而不是7.0),许多人对此表示欢迎。

在数据库中存储BLOBS具有优点和缺点:

一方面,您所有的数据和相关图像或文档都可以在一个地方存储和访问。应用程序用户不需要特殊的网络权限,因为SQL负责提供图像/文件/文档。

另一方面,数据库的大小可能会很大,这取决于要存储的BLOBS的大小和数量。这会影响备份,存储要求,对时间敏感的恢复操作等。

SQL Server 2008引入了文件流。数据库包含指向文件的指针,文件驻留在服务器上而不是数据库中,但是当您备份数据库时,文件也会被备份。

您的备份可能会很大,但最终不会出现孤立的文件/文档/斑点/图像。

我个人的喜好是让数据库存储指针/网络位置,并让文件服务器处理文件。无论如何,文件服务器都针对此类任务进行了更好的优化。


5
没关系,如果您不拥有服务器,则数据库空间和文件空间的价格将为每MB付出更多。将文件放在磁盘上也使故障排除变得更加容易-您如何SELECT image FROM table在SSMS中验证是否有正确的映像?
阿龙贝特朗

7

不要将文件存储在数据库中。

可以在市场上运行任何RDBMS的每个人无一例外都已经拥有专门用于存储文件的数据库,而RDBMS本身正在使用它!该数据库是文件系统。现在,让我们讨论在数据库中存储文件的一些潜在缺点,以及在数据库中存储文件的一些特定缓解因素。

  • 没有文件处理到数据库中的文件。这是什么意思?

    • 程序员谈:您不能寻求(fseek),无法通过异步访问(asyncioepoll)管理资源,也不能sendfile(从内核空间中保存副本)。

    • 实际应用:是否想通过HTTP2 / 3将视频或图片发送到客户端?如果它在数据库中,则首先必须查询它。对于任何查询返回该文件的查询,您都必须等待整个查询结束,然后该文件才能继续进行下一步。在与Web服务器不同的服务器上使用rdbms进行生产安装时,首先必须将文件完全从rdbms传输到Web服务器,而不是通过流传输。但是,如果传输层提供了文件系统抽象(甚至NFS都支持),则可以在文件中途进行搜索,然后立即开始将其流式传输回客户端,而无需缓冲任何不必要的文件。这通常由网络服务器完成nginxApache,PureFTP和ProFTP。

  • 在RDBMS上进行双重复制。由于它确实存在于数据库中,因此您可能会编写两次。一次进入预写日志(WAL),然后再次进入表空间。

  • 没有更新, MVCC意味着什么都不会更新,只有经过修改才能重新复制,然后旧行被标记为过期(已删除)。对文件的任何更新都将需要写入整,而不仅仅是文件整行。文件系统也可以通过数据日志提供此功能,但是您很少需要它。

  • 文件读取和传输以减慢查询速度如果文件本身存储在需要查询的行中,则整行要么必须等待文件被传输,要么必须发出两个单独的查询。

  • DB客户端上的内存使用。DB客户端(libpq,jdbc,odbc,freetds等)可能会将查询缓冲在内存中。当内存中的缓冲区耗尽时,它可能会启动磁盘缓冲区,甚至更糟的是,它可能会退回到内核以分页到磁盘。

  • 通过查询限制,许多数据库都可以在占用大量时间或资源的情况下杀死并获得查询。请记住,文件传输在任何实施中都不会逐项列出。3秒后该查询是否被杀死?还是花了1秒,后端花了2秒来传输文件?不仅是“ itemized”,当99.9%的查询返回1 KB而另一个返回1 GB时,您将如何有效地说明一个查询应该花费多少时间?

  • 无写时复制或重复数据消除 XFS和BTRFS透明地支持写时复制和重复数据消除。这意味着文件系统可以透明地处理到处都具有相同图片或需要第二张图片的情况。但是,如果文件不是独立存在的,而是位于行中或位于存储中,则文件系统很可能无法对其进行重复数据删除。

  • 诚信这里有很多人在谈论诚信。您认为在检测文件系统损坏,使用文件系统或文件系统核心实用程序的应用程序方面有什么更好的选择?连续或离线存储文件,任何文件系统损坏都会掩盖数据库。xfs_repair当文件系统或硬盘驱动器损坏时,它非常擅长恢复,如果失败,则进行数据取证仍然会容易得多。

  • 云迁移如果您想将文件存储在SAN或云上,您将面临更多困难,因为现在存储迁移就是数据库迁移。例如,如果您的文件存储在文件系统上,则可以很容易地将它们移动到S3(并且类似的文件s3fs可以是透明的)。

例外情况

在数据库中存储文件有一些有效的用例,

  • 当你需要向过渡地编辑文件。这意味着编辑文件实际上是您的交易的一部分。或者,如果事务因关系(表)中的数据完整性问题而失败,则您需要具有对文件进行回滚编辑的能力。
  • 当您需要确保文件系统已与数据进行精确版本控制时,您无法承担使它们保持同步的任何风险。
  • 当数据库实际上可以解析文件时,您可以查询它。例如,在PostgreSQL中,拓扑可以是使用PostGIS的查询。在这一点上,虽然它是一个文件,但它也是查询的数据,而不是存储转储。

缓解措施

  • 某些数据库具有“外部管理的资源”的概念,其中数据库可以私下管理磁盘上的文件,例如

  • 一些数据库离线存储或可以存储大型二进制对象,例如Oracle SecureFile。这允许您更新行,而无需重写文件。

  • 某些数据库(例如Oracle)在没有WAL日志的情况下执行其MVC,并且不必进行两次写入文件。

  • 某些数据库(例如SQL Server和Oracle)提供了从文件“流式处理”数据的功能,而无需对其进行文件处理。这可能会或可能不会在与数据库查询不同的连接上运行。但是这里的关键是,尽管您可以流式传输文件(理论上),但我找不到任何证据表明使用该功能的提供商未提供任何产品。例如,NGINX / Apache桥在哪里允许您执行此操作?

  • Oracle通过内部LOB存储(例如SecureFile)提供可选的重复数据删除,压缩和加密。

结论

当您将文件放入数据库中时,最坏的情况是性能和与工具的兼容性非常差。它总是异常依赖于实现。绝不是数据库更好的是一个文件系统,然后将文件系统。无论如何,这都是一个折衷,即使您获得了强大的缓解功能(例如SecureFile的情况),该工具也是如此糟糕,以至于它实际上只不过是一个营销点,除非您的整个堆栈都是由RDBMS提供程序构建的。

保持简单,一般规则是将文件保留在DB之外

您应该如何存储文件,或以这种方式抽象文件系统以对多个租户和用户有效起作用?我偏爱散列文件内容。这些天来这很普遍,而且效果很好。


6

尽管它部分取决于应用程序/环境(包括人员),但我还是很喜欢。

将所有内容保留在数据库中意味着复制适用于文件数据。您需要一种单独的机制来同步FS文件。

在某些应用程序中,无论如何都不应修改文件系统。例如,在生产网站上,我会避免将文件系统用于任何非一次性数据(站点生活在SCM下,数据库中的数据)。

假设我们有多个具有单独权限的用户/应用程序,那么任何文件系统存储都会为DB和FS访问权限的差异提供机会。

我认为对BLOB存储的改进是在有意义的情况下对数据进行分块。如果您只需要20Mb BLOB中的512字节,那么这种类似于扇区的访问将是一大福音,尤其是在您与远程客户端打交道时(同样,部分更新会减少复制流量)。


6

我的投票不会。将数据存储在Amazon S3或Microsft的CDN之类的系统中,并将该URL存储在数据库中。

这样,您就可以确保始终访问数据而无需处理庞大的数据库,从而提高了可靠性。


3

对于postgres:

实际上是很直接的。有一种BYTEA类型可用于存储二进制字符串。默认情况下,没有像针对MS或Oracle提到的那样建立实用程序。因此,存储大量大文件并进行检索会变得很乏味。您还需要在应用程序中进行文件转换(例如使用a ByteStream或类似文件,尽管不知道如何与特定的MS / Oracle file <->数据库解决方案一起使用)。还有一种lo类型有助于管理BLOB,因为这些类型的某些内部管理可能无法跟踪引用。


-4

分享我对SQL Server女士和大量文件的经验。我们将文件保存在文件服务器上。数据库有两个表,一个表用于文件夹和访问凭据,一个表用于文件名。维护数据库和文件很容易。您甚至可以跨服务器轻松地移动文件,只需要修改文件夹表即可。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.