Jac*_*las 147 database-design blob
存储与数据库中数据相关的二进制文件的最佳位置是什么?你应该:
(1) 的优点是(除其他外)事务的原子性得以保留。代价是您可能会显着增加存储(和相关的流/备份)要求
(3) 的目标是在某种程度上保留原子性 - 如果您可以强制您正在写入的文件系统不允许更改或删除文件,并且始终具有正确的哈希作为文件名。这个想法是在允许引用哈希的插入/更新之前将文件写入文件系统 - 如果此事务在文件系统写入之后但在数据库 DML 之前失败,那很好,因为文件系统“假装”是所有的存储库可能的文件和哈希值 - 是否有一些文件没有被指向并不重要(如果你小心的话,你可以定期清理它们)
编辑:
看起来一些 RDBMS 以各自的方式涵盖了这一点 - 我很想知道其他人是如何做到的 - 特别是在 postgres 的解决方案中
Tan*_*ena 63
使用 blob 存储在数据库中
一个缺点是它会使您的数据库文件非常大,并且可能太大而无法使用现有设置进行备份。一个优点是完整性和原子性。
使用数据库中的链接存储在文件系统上
我在这样做时遇到了如此可怕的灾难,而且人们不断提出建议让我感到害怕。一些灾难包括:
C:\一路的.doc,而不是NT的所有版本都能够处理长路径。 存储在文件系统中但重命名为内容的散列并将散列存储在数据库中
根据我对上述场景的解释,我工作的最后一个地方是这样做的。他们认为这是组织无法获得大型数据库经验(任何大于 40G 的东西都被规定为“太大”)、公司无法购买大型硬盘驱动器以及无法购买更现代的后备箱之间的折衷方案。解决方案,以及摆脱我上面确定的风险 #1 和 #3 的需要。
我的观点是,在多服务器场景中,作为 blob 存储在数据库中是更好的解决方案,并且更具可扩展性,尤其是在故障转移和可用性问题上。
gbn*_*gbn 29
完整数据完整性的第 1 名。如果您不关心数据质量,请使用其他选项。就这么简单。
无论如何,大多数 RDBMS 都对存储 BLOB(例如 SQL Server 文件流)进行了优化
ik_*_*elf 22
如果使用 oracle,请查看 dbfs 和 Secure Files。
安全文件说明了一切,确保数据库中的所有数据安全。它以高球组织。Secure Files 是 lob 的现代化版本,应该被激活。
dbfs 是数据库中的文件系统。您可以像网络文件系统一样在 Linux 主机上安装它。它真的很强大。请参阅博客它还有很多选项可以根据您的特定需求进行调整。作为一名 dba,给定一个文件系统(基于数据库,安装在 Linux 上),我在其上创建了一个 Oracle 数据库,没有任何问题。(一个数据库,存储在...数据库中)。并不是说这会很有用,但它确实显示了力量。
更多的优点是:可用性、备份、恢复,所有读取的其他关系数据都一致。
有时给出大小作为不在数据库中存储文档的原因。该数据可能必须以任何方式备份,因此这不是不存储在数据库中的好理由。特别是在将旧文档视为只读的情况下,很容易使数据库的大部分内容变为只读。在这种情况下,数据库的那些部分不再需要高频率备份。
表中对数据库外内容的引用是不安全的。它可以被操纵,很难检查并且很容易丢失。交易怎么样?该数据库为所有这些问题提供了解决方案。使用 Oracle DBFS,您可以将您的文档提供给非数据库应用程序,而他们甚至不知道他们正在查看数据库。
最后一个大惊喜,dbfs 文件系统的性能通常优于常规文件系统。如果文件大于几个块,则尤其如此。
Eva*_*oll 21
每个人,无一例外,可以运行市场上任何 RDBMS 的人都已经拥有一个专门用于存储文件的数据库,而 RDBMS 本身也在使用它!该数据库就是文件系统。现在让我们谈谈在数据库中存储文件的一些潜在缺点,以及在数据库中存储文件的一些特定缓解因素。
数据库中的文件没有文件句柄。这是什么意思?
程序员谈话:您不能寻求 ( fseek),无法通过异步访问 (asyncio或epoll)来管理资源,没有sendfile(从内核空间保存副本)。
实际应用:想通过HTTP2/3向客户端发送视频或图片?如果它在数据库中,那么您首先必须查询它。对于返回该文件的任何查询,您必须等待整个查询结束,然后该文件才能移动到下一步。在与 Web 服务器不同的服务器上使用 rdbms 进行生产安装时,您首先必须将文件完全从 rdbms 传输到 Web 服务器,而不是通过流式传输。但是,如果传输层提供了文件系统抽象(甚至 NFS 支持),您可以在文件中途寻找并立即开始将其流回客户端,而无需缓冲任何不必要的文件。这通常由网络服务器完成nginx、Apache、PureFTP 和 ProFTP。
RDBMS 上的双重复制。由于它位于数据库中,因此您可能会编写两次。一次写入预写日志 (WAL),然后再次进入表空间。
没有更新, MVCC意味着什么都不会更新,只会通过修改重新复制,然后旧行被标记为过期(删除)。对文件的任何更新都需要写入整行,而不仅仅是整行的文件。文件系统也可以通过数据日志提供此功能,但您很少需要它。
文件读取和传输以减慢查询速度如果文件本身存储在您需要查询的行上,则整行要么必须等待文件传输,要么您必须发出两个单独的查询.
数据库客户端上的内存使用。DB 客户端(libpq、jdbc、odbc、freetds 等)等可能会在内存中缓冲查询。当内存中的缓冲区耗尽时,它可能会启动一个磁盘缓冲区,或者更糟糕的是,它可能会回退到内核以分页到磁盘。
当查询占用太多时间或资源时,查询限制许多数据库提供了终止和获取查询的能力。请记住,文件传输不会在任何实现中逐项列出。该查询是否在 3 秒后被终止?还是只用了 1 秒,而后端用了 2 秒传输文件?不仅仅是“逐项列出”,当 99.9% 的查询返回 1 KB 而另一个查询返回 1 GB 时,您将如何有效地说明查询应该花费多长时间?
无写入时复制或重复数据删除XFS 和 BTRFS 透明地支持写入时复制和重复数据删除。这意味着在任何地方都有相同的图片,或者需要它的第二个副本可以由文件系统透明地处理。但是,如果文件不是独立存在的,而是在一行中或在存储中,则文件系统可能无法对其进行重复数据删除。
诚信很多人在这里都在谈论诚信。您认为在检测文件系统损坏、使用文件系统或文件系统核心实用程序的应用程序方面,什么更好?将文件连续存储或离线存储,任何文件系统损坏都将掩盖数据库。xfs_repair当文件系统或硬盘损坏时,它非常擅长恢复,如果失败,进行数据取证仍然容易得多。
云迁移如果您想将文件存储在 SAN 或云上,您将遇到更多困难,因为现在存储迁移是数据库迁移。例如,如果您的文件存储在文件系统上,您可以很容易地将它们移动到 S3(并且类似的s3fs东西可以是透明的)。
在数据库中存储文件有一些有效的用例,
某些数据库有“外部管理资源”的概念,其中数据库要么私下管理磁盘上的文件,例如
PostgreSQL 通过大对象基础结构在事务期间为资源提供文件句柄。
SQL Server 2017 的文件流基础结构提供了在事务期间持续的临时访问,您可以使用它来获取文件路径并打开文件句柄。
Oracle 提供BFILE(这与其内部 LOB 内容无关,称为SecureFile
一些数据库以外部方式或可以存储大型二进制对象,例如 Oracle SecureFile。这允许您更新行,而无需重写文件。
某些数据库(如 Oracle)在没有 WAL 日志的情况下执行 MVC,并且不必将文件写入双倍。
一些数据库,如 SQL Server 和 Oracle,提供从文件“流”数据的能力,而无需文件句柄。这可能会或可能不会在与数据库查询不同的连接上运行。但这里的关键是,虽然您可以流式传输文件(理论上),但我找不到任何不是由使用该功能的提供商制造的产品的任何证据。例如,允许您执行此操作的 NGINX/Apache 桥在何处?
Oracle 通过内部 LOB 存储(如 SecureFile)提供可选的重复数据删除、压缩和加密。
将文件放入数据库的最坏情况对性能和工具兼容性非常不利。它总是特别依赖于实现。数据库在作为文件系统方面绝不比作为文件系统更好。在各个方面,这都是一种妥协,即使您获得了强大的缓解功能(例如 SecureFile 的情况),该工具也非常糟糕,除非您的整个堆栈是由 RDBMS 提供商构建的,否则它实际上只是一个营销点。
保持简单,一般规则是将文件保留在 DB 之外。
您应该如何存储文件或以这种方式抽象文件系统以有效地为多个租户和用户运行?我偏爱散列文件内容。这在当今很常见,并且效果很好。
Tek*_*Tek 17
不要这样做。
将文件存储在数据库中确实没有好处。
当你自己思考时,是不是已经感觉很奇怪和可疑:
我应该将文件存储在数据库还是文件系统中?
更好的是,大声说出来。
说到事实:
“优点”...但不完全是:
我真的不想有偏见,但我认为没有更多要补充的了。如果你仔细想想,专业人士并不是那么好。
如果我忘记了下面的评论,同时继续阅读下面的内容。
缺点:
优点:
缺点:
现在你问自己,坚持你的意思是没有缺点?!怎么来的?
这里最大的错误是人们试图用锤子拧螺丝。
主要原因,我会说唯一的原因是因为文件链接。
这是数据库不打算解决的问题。如果你仔细想想,这甚至听起来很傻。
“数据库将修复我的文件链接问题。”
在现实中,从逻辑上讲,应用程序实际上应该负责处理和提供链接。
这也将抽象出本机路径,使应用程序更可移植、更易于维护,并允许在不破坏任何内容的情况下切换到任何类型的文件系统。
至于如何实现它超出了本答案的范围,但您可以看一下可以说是使用最广泛的网络语言 (PHP) 的一般示例:
https://github.com/symfony/Routing
https://github.com/kriswallsmith/assetic
这两个加在一起真的很强大。
Nat*_*lly 16
我认为这里的正确答案很大程度上取决于您的申请以及这些文件的重要性。
对于文档管理系统或存储文档的可恢复性至关重要的系统(因此大多数与财务、人力资源或 CRM 相关的事情),内联存储文档或使用您最喜欢的数据库供应商的专有文档技术似乎是正确的做法。
但是,在许多应用中,我认为相反的决定是合适的。
Helpdesk 系统和 wiki 类型的系统是我认为将数据保留在数据库之外很有意义的系统。我相信有些人,比如 Jira,实际上提供了一个选项来选择是否要内联存储文档。
对于中型企业,在线存储票务系统文档可能意味着以兆字节为单位的压缩备份和以千兆字节为单位的压缩备份之间的差异。
我个人更愿意在几分钟内将票务系统重新上线,并在几个小时内处理(通常不太重要的)文件,而不是通过必须恢复来增加我的“它坏了,CTO 喘不过气来”的 RTO并从更大的备份中重播日志。
将文档分开还有其他好处。
我认为#2 和#3 的混合组合可能很聪明。保留原始文件名,但计算并存储文档的哈希/校验和,以便您有一些参考点,以便在有人移动或重命名文件时帮助恢复。
使用原始文件名存储文件意味着应用程序可以直接从文件系统中提取它们并通过网络发送它们,或者在胖客户端世界中,甚至可以将用户直接指向文件服务器。
Chr*_*ers 10
我想在这里添加我的经验以进行权衡。至少在 PostgreSQL 中,就 db 服务器而言,性能影响非常小。大 blob 存储在单独的文件中,而不是在主堆表中,以便将它们移出可能计算大量记录的操作。其他数据库可能会做类似的事情。
主要优点是能够将所有相关数据保存在一个地方以实现原子性和备份目的。这大大降低了出错的可能性。
主要的缺点不是我在上面看到的,那就是前端的内存使用。我不知道每个 db 是如何处理这个的,所以这可能取决于实现,但对于 PostgreSQL,数据以转义的 ASCII 字符串形式出现(可能是十六进制,可能带有内联转义)。然后必须在前端将其转换回二进制。我见过的许多框架都涉及传递值(不是作为参考),然后基于它构造一个新的二进制字符串。我计算出使用 Perl 来做这件事最终会使用很多倍的原始二进制文件的内存来完成。
结论:如果文件只是偶尔被访问,我会存储在数据库中。如果它们被频繁且重复地访问,至少使用 PostgreSQL,我认为成本大于收益。
过去,微软大肆宣传在数据库中存储图像(和类似的 blob 数据类型)的能力。这是 SQL Server 2000 的一个很酷的新功能(我很确定它是 2000,而不是 7.0),很多人都加入了这个潮流。
将 BLOBS 存储在数据库中有利有弊:
一方面,您的所有数据和相关图像或文档都可以在一个地方存储和访问。应用程序用户不需要特殊的网络权限,因为提供图像/文件/文档的是 SQL。
另一方面,您的数据库可能会变得非常大,具体取决于您存储的 BLOBS 的大小和数量。这会影响备份、存储要求、时间敏感的恢复操作等。
SQL Server 2008 引入了文件流。数据库包含指向文件的指针,文件驻留在服务器上而不是在数据库中,但是当您备份数据库时,文件也会被备份。
您的备份可能会变得非常大,但您最终不会得到孤立的文件/文档/blob/图像。
我个人的偏好是让数据库存储指针/网络位置,并让文件服务器处理文件。无论如何,文件服务器都针对此类任务进行了更好的优化。
小智 7
我的一票都不赞成。将数据存储在 Amazon S3 或 Microsft 的 CDN 等系统中,并将该 URL 存储在数据库中。
通过这种方式,您可以获得始终可访问数据的可靠性,而无需处理庞大的数据库。
虽然它部分取决于应用程序/环境(包括人),但我会选择 blob。
将所有内容保存在数据库中意味着复制适用于文件数据。您需要一个单独的机制来同步 FS 文件。
在某些应用程序中,无论如何都不应该修改文件系统。例如,在生产网站上,我会避免将文件系统用于任何非一次性数据(站点位于 SCM 下,数据库中的数据)。
假设我们有多个具有单独权限的用户/应用程序,那么任何文件系统存储都为 DB 和 FS 访问权限的差异提供了机会。
我考虑对 BLOB 存储进行的改进是对数据进行分块(如果有意义的话);如果您只需要 20Mb BLOB 中的 512 个字节,这种类似扇区的访问是一个真正的福音,尤其是当您处理远程客户端时(同样,部分更新创建的复制流量要少得多)。