我当前正在创建一个Web应用程序,允许用户存储和共享1 MB-10 MB的文件。
在我看来,将文件存储在数据库中将大大降低数据库访问速度。
这是一个有效的问题吗?将文件存储在文件系统中并将文件名和路径保存在数据库中是否更好?使用数据库时,是否有与存储文件有关的最佳实践?
我正在该项目的PHP和MySQL中工作,但是对于大多数环境(Ruby on Rails,PHP,.NET)和数据库(MySQL,PostgreSQL)都是相同的问题。
我当前正在创建一个Web应用程序,允许用户存储和共享1 MB-10 MB的文件。
在我看来,将文件存储在数据库中将大大降低数据库访问速度。
这是一个有效的问题吗?将文件存储在文件系统中并将文件名和路径保存在数据库中是否更好?使用数据库时,是否有与存储文件有关的最佳实践?
我正在该项目的PHP和MySQL中工作,但是对于大多数环境(Ruby on Rails,PHP,.NET)和数据库(MySQL,PostgreSQL)都是相同的问题。
Answers:
支持将文件存储在数据库中的原因:
禁止在数据库中存储文件的原因:
FILESTREAM
对象)并且需要迁移到其他数据库系统,则可移植性可能是一个问题。IMO认为文件在数据库中的存储是否为“不良”,需要有关情况和要求的更多信息。文件的大小和/或数量是否总是很小?是否没有使用云存储的计划?这些文件是否可以在网站或Windows应用程序之类的二进制可执行文件中提供?
总的来说,我的经验发现,即使考虑到缺少ACID和存在孤儿的可能性,存储路径对于企业来说也较便宜。但是,这并不意味着互联网上不会出现因缺乏ACID控制而导致文件存储出错的故事,而是意味着总体上该解决方案更易于构建,理解和维护。
在许多情况下,这是一个坏主意。它将使数据库文件膨胀,并导致多个性能问题。如果将斑点粘贴到具有大量列的表中,则情况更糟。
然而!某些数据库(例如SQL Server)具有FILESTREAM列类型。在这种情况下,您的数据实际上存储在数据库服务器上的单独文件中,并且表中仅保存该文件的ID。在这种情况下,我没有太多理由不将数据保留在SQL Server中。这些文件将自动包含在服务器备份中,并且数据库和文件永远不会不同步。Tony建议存储文件名的问题在于数据库和文件系统可能不同步。数据库在磁盘上删除文件后将声明文件存在。如果某个进程正在修改数据库,然后崩溃,则文件和数据库将不匹配(即,ACID与数据库外部的文件不匹配)。
是的,这是一个坏习惯。
性能对数据库的影响:
SELECT
使用任何BLOB列进行操作,则始终将进行磁盘访问,而如果没有BLOB,则有机会直接从RAM中获取数据(将优化高吞吐量DB以适合RAM中的表);速度优势- 无!尽管某些较旧的文件系统无法处理包含数百万个文件的目录,但大多数现代文件系统都没有问题,实际上使用的数据结构与BD(通常为B树)相同。例如ext4(默认Linux文件系统)使用Htree。
结论:这将影响数据库性能,并且不会提高文件检索性能。
此外,由于你在谈论的Web应用程序-利用现代网络服务器,它可以做到直接从文件系统提供静态文件sendfile()
系统调用是巨大的性能提升。如果要从数据库获取文件,这当然是不可能的。以这个基准测试为例,该测试显示Ngnix在低端笔记本电脑上以1000个并发连接进行25K req / s。这种负载将炸毁任何类型的数据库。
我会很务实,并遵循“不要优化”的原则。提供当前有意义的解决方案,并为您提供适当实施的开发资源。有很多潜在的问题。但是这些并不一定会成为真正的问题。例如,如果您有100个用户,则可能不会有问题。如果您有100,000或10,000,000用户,则可能是一个问题。但是,在后一种情况下,应该有更多的发展资源来处理所有问题的基础。
但是将数据存储在数据库中确实可以使您免于处理其他问题,例如,文件应存储在何处,应如何备份等。由于您正在编写Web应用程序,因此出于安全原因,这将是一个很好的主意为了确保承载应用程序的进程没有对该文件系统的写访问权,因此您需要配置服务器,以便该进程对存储数据的文件夹具有读/写访问权。
我个人选择将数据存储在数据库中,但要确保直到真正需要它们时才读取BLOBS,即在包含博客的那些表上不执行“ SELECT * FROM ...”。而且,如果确实遇到性能问题,我将确保该设计可以轻松地将数据移出数据库,移入文件系统。例如,将文件信息存储在单独的“ 文件”表中,从而使文件信息远离其他业务实体。
假设您有一个File类来表示在数据库中读取的文件,那么以后将其移出对编码的影响将很小。
微软几年前发布了一份有关此的白皮书。它专注于SqlServer,但是您可能会在其中找到一些有趣的信息:
他们结论的一个非常简洁的版本是:
在比较NTFS文件系统和SQL Server 2005时,SQL Server可以更有效地处理小于256KB的BLOBS,而大于1MB的BLOBS可以更有效地处理NTFS。
我建议您针对特定用例编写一些小型测试。请记住,您必须提防缓存效果。(我第一次惊讶于磁盘保存速度似乎比物理上更高的吞吐量!)
将文件存储在数据库外部的古老传统智慧可能不再成立。原则上,我倾向于完整性而不是速度,而对于现代DBMS,您可以同时拥有两者。
汤姆·凯特(Tom Kyte)似乎同意:
我知道将要长时间保存在数据库外部的数据没有任何优势。
如果它在数据库中,我可以
确保它是专业管理的
支持
可恢复的(与其余数据一起)
固定的
可扩展的(尝试将100,000个文档放在一个目录中,现在,将它们放在表中-“缩放”一个-不是目录)
我可以轻松取消删除(闪回)
我有锁
我读过一致性...
是。
如果从文件系统提供文件,则Web服务器可以使用BSD或Linux上的内核代码(例如sendfile())将文件直接复制到套接字。这是非常快速和高效的。
从数据库中提供文件服务意味着您必须将数据从数据库服务器的磁盘复制到数据库服务器内存,然后从数据库服务器的内存复制到数据库服务器的网络端口,然后从网络复制到Web服务器进程,然后再复制到数据库服务器。传出网络连接。
除非确实有很好的理由,否则最好从文件系统提供静态文件。
著名的汤姆·凯特(Tom Kyte)写道,他们(甲骨文公司)正在使用甲骨文数据库作为文件服务器,并且它的运行状况非常好,甚至比普通文件系统还要快,并且具有完全的事务性,没有性能损失并且具有单个备份。
是的,但是请注意,它们是Oracle DB的生产者,对于其他任何用户,都存在成本问题。使用商业数据库(例如Oracle)来存储文件根本没有成本效益。
但是,例如使用PostgreSQL,您可以仅运行另一个数据库实例仅用于blob存储。然后,您将获得全面的交易支持。但是事务性消耗数据库空间。数据库需要为多个并发事务存储多个blob实例。在PostgreSQL上,这是最痛苦的,因为此数据库存储为事务而创建的blob的副本,即使不再需要它们也要存储,直到VACUUM处理完成为止。
另一方面,对于文件系统存储,当有人修改文件时,您必须非常小心,因为可以回滚事务,并且必须保留文件副本,直到不再显示旧版本为止。
在仅添加和删除文件且对文件的事务访问不成问题的系统中,文件系统存储将是恕我直言的最佳选择。
您可能会遇到以下一些问题:
SELECT *
即使您不需要blob,使用涉及大blob的行进行a 也会花费很长时间(当然,您应该进行特定的选择,但是有时应用程序是这样编写的)当然,您还会获得一些好处:
就我个人而言,我不这样做,因为我发现缺点比优点多得多。但是如上所述,它完全取决于您的用例。