在DB中存储图像 – 是或否?

所以我正在使用一个应用程序在数据库中存储图像。 你对此有什么看法? 我更喜欢在文件系统中存储位置,而不是将其直接存储在数据库中。

你认为什么是利弊?

我负责pipe理许多TB图像的一些应用程序。 我们发现在数据库中存储文件path是最好的。

有几个问题:

  • 数据库存储通常比文件系统存储更昂贵
  • 您可以使用标准的现成产品来超级加速文件系统访问
    • 例如,许多Web服务器使用操作系统的sendfile()系统调用来将文件直接从文件系统asynchronous发送到networking接口。 存储在数据库中的图像不受益于此优化。
  • 诸如networking服务器之类的东西,不需要特殊的编码或处理来访问文件系统中的图像
  • 数据库胜出,图像和元数据之间的交易完整性非常重要。
    • pipe理数据库元数据和文件系统数据之间的完整性更为复杂
    • (在Web应用程序的上下文中)保证数据已经被刷新到文件系统上的磁盘上是困难的

与大多数问题一样,它并不像听起来那么简单。 在某些情况下,将图像存储在数据库中是有意义的。

  • 您正在存储正在dynamic变化的图像,说发票,你想要发票,因为它是在2007年1月1日?
  • 政府希望你保持6年的历史
  • 存储在数据库中的图像不需要不同的备份策略。 存储在文件系统上的图像可以
  • 如果它们在数据库中,则更容易控制对图像的访问。 空闲pipe理员可以访问磁盘上的任何文件夹。 需要一个确定的pipe理员去窥探数据库来提取图像

另一方面也有相关的问题

  • 需要额外的代码来提取和stream式传输图像
  • 延迟可能比直接文件访问慢
  • 数据库服务器负载较重

文件存储。 Facebook的工程师对此有了一个很好的讨论。 一个拿走是要知道目录中的文件的实际限制。

在干草堆针:数十亿照片的有效存储

这可能是一个很长的一个镜头,但是如果你正在使用(或计划使用)SQL Server 2008,我build议看看新的FileStream数据types。

FileStream解决了将文件存储在数据库中的大部分问题:

  1. Blob实际上是作为文件存储在一个文件夹中的。
  2. 可以使用数据库连接通过文件系统访问Blob。
  3. 备份已集成。
  4. 迁移“正常”。

但是,SQL的“透明数据encryption”不会encryptionFileStream对象,所以如果这是一个考虑因素,最好将它们存储为varbinary。

来自MSDN文章:

Transact-SQL语句可以插入,更新,查询,search和备份FILESTREAM数据。 Win32文件系统接口提供对数据的stream式访问。
FILESTREAM使用NT系统caching来caching文件数据。 这有助于减lessFILESTREAM数据可能对数据库引擎性能造成的影响。 SQL Server缓冲池未被使用; 因此,该内存可用于查询处理。

数据库中的文件path绝对是我们要走的路 – 我已经从客户那里听到了有关TB图像的故事,它成为一个噩梦,试图在数据库中存储大量图像 – 单靠性能的提升太多了。

根据我的经验,有时最简单的解决scheme是根据主键命名图像 。 所以很容易find属于特定logging的图像,反之亦然。 但同时你不会在数据库中存储任何关于图像的东西

这里的诀窍是不要成为狂热分子。

在这里需要注意的一点是,专业文件系统阵营中没有人列出特定的文件系统。 这是否意味着从FAT16到ZFS的所有内容都能轻松击败每个数据库?

没有。

事实是,即使我们只是在谈论原始速度,许多数据库也打败了很多文件系统。

正确的做法是为您的准确情况做出正确的决定,为此,您需要一些数字和一些用例估计值。

在您必须确保参照完整性和ACID合规性的地方,需要将图像存储在数据库中。

你不能保证数据库中存储的图像和元数据引用同一个文件。 换句话说,不可能保证文件系统上的文件只是在与元数据同时和在同一事务中被改变。

正如其他人所说,SQL 2008带有一个文件streamtypes,允许您将文件名或标识符作为指针存储在数据库中,并自动将该映像存储在您的文件系统中,这是一个非常棒的场景。

如果你在一个较旧的数据库上,那么我会说,如果你将它存储为blob数据,那么你真的不会在searchfunction的方式中从数据库中得到任何东西,所以这可能是最好的在一个文件系统上存储一个地址,并以这种方式存储图像。

这样,你也可以节省文件系统的空间,因为你只能保存文件系统的精确空间,甚至压缩空间。

此外,您可以决定保存一些结构或元素,这些结构或元素允许您在没有任何数据库命中的情况下浏览文件系统中的原始图像,或将这些文件批量传输到另一个系统,硬盘驱动器,S3或其他场景 – 更新位置你的程序,但保持结构,再次没有太多的尝试,试图增加存储时,你的数据库出来的图像。

也许,它也可以让你把一些caching元素,基于常见的图像url到你的网页引擎/程序,所以你也保存在那里。

应该将不经常编辑的小静态图像(不超过几个兆字节)存储在数据库中。 这种方法有几个好处,包括更容易移植(图像与数据库传输),更容易备份/恢复(图像备份与数据库)和更好的可伸缩性(一个文件系统文件夹与成千上万的小缩略图文件听起来像一个可扩展性的噩梦我)。

从数据库中提供图像很容易,只需实现一个http处理程序,它将从数据库服务器返回的字节数组作为二进制stream提供服务。

这是一个有趣的关于这个话题的白皮书。

BLOB或不BLOB:数据库或文件系统中的大型对象存储

答案是“这取决于”。 当然,这将取决于数据库服务器及其对blob存储的方法。 它还取决于存储在Blob中的数据的types,以及如何访问这些数据。

较小的文件可以使用数据库作为存储机制高效地存储和交付。 较大的文件可能最好使用文件系统进行存储,尤其是在经常修改/更新的情况下。 (blob碎片成为性能问题。)

这里还有一点要记住。 支持使用数据库来存储斑点的原因之一是符合ACID。 但是,白皮书(SQL Server的Bulk Logged选项)中使用的SQL Server吞吐量加倍的testing人员将ACID中的“D”有效地更改为“d”,因为blob数据未logging交易的初始写入。 因此,如果完全符合ACID是您的系统的重要要求,那么在比较文件I / O与数据库blob I / O时,将数据库写入的SQL Server吞吐量减半。

有一件事我还没有看到任何人提到,但绝对值得注意的是,在大多数文件系统中存储大量图像也存在相关的问题。 例如,如果采取上述方法并在主键之后命名每个图像文件,则在大多数文件系统上,如果尝试将所有图像放入一个大目录(一旦达到大量图像),就会遇到问题例如成千上万或数百万)。

一旦通用的解决scheme是将它们散列成一个平衡的子目录树。

没有人提到过,DB保证primefaces动作,事务完整性和并发处理。 即使是文件系统的完整性也不在乎 – 那么你怎么知道你的文件名还是正确的呢?

如果你在一个文件系统中有你的图像,并且有人在你正在编写一个新版本甚至删除这个文件的时候正在读这个文件 – 会发生什么?

我们使用blob是因为它们更易于pipe理(备份,复制,传输)。 他们为我们工作得很好。

只将文件path存储到数据库中的问题是数据库的完整性不能再被强制。

如果文件path指向的实际映像不可用,则数据库在不知不觉中会出现完整性错误。

假设图像是被追踪的实际数据,并且它们可以在一个集成数据库中更容易地pipe理(图像不会突然消失),而不必与某种文件系统连接(如果文件系统是独立访问的,图像可能突然“消失”),我会去直接存储他们作为BLOB或这样的。

在我曾经工作过的公司,我们在Oracle 8i(然后是9i)数据库中存储了1.55亿张图片。 价值7.5TB。

通常,我坚决反对以最昂贵和最难的方式来扩展您的基础架构(数据库)的一部分,并将所有的负载放入其中。 另一方面:它大大简化了备份策略,特别是当你有多个Web服务器,并且需要以某种方式保持数据同步时。

像大多数其他事情一样,这取决于预期的规模和预算。

我们已经实现了一个文件成像系统,它将所有的图像存储在SQL2005 blob字段中。 目前有几百GB,我们正在看到出色的响应时间,很less或没有性能下降。 另外,在法规遵从性方面,我们有一个中间件层,将新发布的文档存档到光盘自动点唱机系统,并将其作为标准的NTFS文件系统公开。

我们对结果非常满意,特别是在以下方面:

  1. 易于复制和备份
  2. 能够轻松实现文档版本控制系统

如果这是基于networking的应用程序,那么将图像存储在第三方存储传送networking(如亚马逊的S3或Nirvanix平台)上可能会有好处。

假设:应用程序是基于Web的/基于Web的

我很惊讶没有人真的提到过这个…委托给其他专家 – > 使用第三方图像/文件托pipe提供商

将您的文件存储在付费的在线服务上

  • 亚马逊S3
  • 摩梭云存储

另一个StackOverflow线程在这里讨论这个问题 。

这个线程解释了为什么你应该使用第三方托pipe服务提供商。

这是非常值得的。 他们有效地存储它。 没有带宽从您的服务器上传到客户端请求等

如果您不在SQL Server 2008上,并且将特定映像文件放在数据库中有一些可靠的原因,那么您可以采用“两者”的方法,并将文件系统用作临时caching,并将该数据库用作主存储库。

例如,您的业务逻辑可以检查光盘上是否存在图像文件,然后在提供时从数据库中检索,必要时进行检索。 这为您带来了多个Web服务器的function,并减less了同步问题。

我不确定这是多less“真实世界”的例子,但我现在有一个应用程序存储交易卡游戏的细节,包括卡的图像。 当然,数据库的logging数目迄今为止只有2851条logging,但是考虑到某些卡片已经被多次释放并且具有replace的graphics,实际上在扫描graphics的“主要方形”然后dynamic地请求时为卡片生成边框和杂项效果。

这个图像库的原始创build者创build了一个数据访问类,根据请求呈现图像,并且对于查看和个人卡片来说,它的速度非常快。

这也可以在释放新卡时简化部署/更新,而不是压缩整个图像文件夹并将其发送到pipe道,并确保创build正确的文件夹结构,我只需更新数据库并让用户再次下载。 这目前大小高达56MB,这不是很好,但我正在为将来的版本的增量更新function。 此外,还有一个“无图像”版本的应用程序,允许那些通过拨号来获得应用程序,而没有下载延迟。

此解决scheme迄今为止工作良好,因为应用程序本身作为桌面上的单个实例。 有一个网站,所有这些数据被存档在线访问,但我绝不会使用相同的解决scheme。 我同意文件访问将是可取的,因为它会更好地扩大到图像请求的频率和数量。

希望这不是太啰嗦,但我看到了这个话题,并希望从一个相对成功的中小型应用程序中提供一些我的见解。

SQL Server 2008提供了一个两全其美的解决scheme:文件stream数据types 。

像常规表一样pipe理它,并具有文件系统的性能。

这取决于你要存储的图像的数量,也取决于它们的大小。 我曾经使用数据库来存储图像,我的经验相当不错。

IMO,使用数据库来存储图像的优点,

答:您不需要FS结构来保存图像
B.当需要存储更多数量的项目时,数据库索引比FS树更好
C.智能调优的数据库在caching查询结果方面performance不错
D.备份很简单。 如果您有复制设置和内容从服务器附近传递给用户,它也工作得很好。 在这种情况下,不需要显式同步。

如果您的映像将会很小(比如<64k),并且您的数据库的存储引擎支持内联(logging)BLOB,则由于不需要间接访问(实现参照的局部性),因此可以进一步提高性能。

在处理less量巨大尺寸的图像时,存储图像可能不太合适。 在db中存储图像的另一个问题是,元数据如创build,修改date必须由您的应用程序处理。

我最近创build了一个将PDF / Word文件存储在MySQL表中的PHP / MySQL应用程序(到目前为止,每个文件大小为40MB)。

优点:

  • 上传的文件与其他所有内容一起复制到备份服务器,不需要单独的备份策略(安心)。
  • 设置Web服务器稍微简单一点,因为我不需要上传/文件夹,并告诉我的所有应用程序它在哪里。
  • 我可以使用事务进行编辑,以提高数据的完整性 – 我不必担心孤立和丢失的文件

缺点:

  • mysqldump现在需要一个looooong时间,因为其中一个表中有500MB的文件数据。
  • 与文件系统相比,整体来说内存/ CPU效率不高

我会叫我的实现成功,它会照顾备份需求并简化项目的布局。 对于使用该应用程序的20-30人来说,performance还不错。

我的经验,我不得不pipe理这两种情况:图像存储在数据库和文件系统上的图像存储在path中的path。

第一个解决scheme是数据库中的图像,因为你的数据访问层只能处理数据库对象, 但只有在处理低数字时才是好事。

当处理二进制大对象时,显然数据库访问性能正在下降,数据库维度将会增长很多,从而导致性能再次下降……通常数据库空间比文件系统空间要贵得多。

另一方面,在文件系统中存储较大的二进制对象会导致备份计划必须同时考虑数据库和文件系统,这对于某些系统来说可能是个问题。

去文件系统的另一个原因是,当你必须与第三方访问共享你的图像数据(或声音,video,不pipe),在这些日子里,我正在开发一个networking应用程序,使用图像,必须从“外部“我的网上农场这样一个数据库访问来检索二进制数据是根本不可能的。 所以有时候也有devise考虑因素会促使你select。

考虑一下,在做这个select时,如果在访问二进制对象时必须处理权限和身份validation:当数据存储在数据库中时,这些必要条件通常可以以更简单的方式解决。

我曾经在一个image processing应用程序工作。 我们将上传的图像存储在类似/ images / [today's date] / [id number]的目录中。 但是我们也从图像中提取元数据(exif数据),并将其存储在数据库中,以及时间戳等。

在以前的项目中,我将图像存储在文件系统上,导致了很多备份,复制以及文件系统与数据库不同步的问题。

在我最近的项目中,我将图像存储在数据库中,并将它们caching在文件系统上,并且效果非常好。 到目前为止,我一直没有问题。

其次是文件path上的build议。 我曾参与过几个需要pipe理大型资产集合的项目,而任何直接在数据库中存储的尝试都会导致长期的痛苦和沮丧。

我能想到的唯一真正的“专业人士”将其存储在数据库中,可以轻松实现个人图像资产。 如果没有要使用的文件path,并且所有图像都直接从数据库中stream出,则用户find不应该访问的文件没有危险。

这看起来好像用一个中间脚本从一个不可访问的文件存储中提取数据会更好地解决这个问题。 所以数据库存储不是非常必要的。

在街道上的字是,除非你是一个数据库供应商试图certificate你的数据库可以做到这一点(比如说,微软吹嘘Terraserver在SQL Server中存储一个bajillion图像),这不是一个好主意。 当替代scheme – 在数据库中的文件服务器和path上存储图像更加容易时,为什么要麻烦? Blob领域就像SUV的越野能力 – 大多数人不使用它们,那些通常会遇到困难的人,然后是那些做的,但只是为了它的乐趣。

在数据库中存储图像仍然意味着图像数据在文件系统中的某个地方结束,但是被遮住了,所以不能直接访问它。

+ VES:

  • 数据库完整性
  • 它易于pipe理,因为您不必担心在添加或删除映像时保持文件系统同步

-ves:

  • 性能损失 – 数据库查找通常比文件系统查找要慢
  • 你不能直接编辑图像(剪裁,resize)

这两种方法都很常见和实践。 看看优点和缺点。 无论哪种方式,你都必须考虑如何克服缺点。 在数据库中存储通常意味着调整数据库参数并实现某种caching。 使用文件系统需要你find一种方法来保持文件系统+数据库的同步。