在数据库中存储图像 - 是还是否?
题
因此,我正在使用一个将图像大量存储在数据库中的应用程序。您对此有何看法?我更喜欢将位置存储在文件系统中,而不是直接存储在数据库中。
您认为优点/缺点是什么?
没有正确的解决方案
其他提示
我负责一些管理大量图像的应用程序。我们发现存储 文件路径 在数据库中最好。
有几个问题:
- 数据库存储通常比文件系统存储更昂贵
- 您可以使用标准的现成产品来超级加速文件系统访问
- 例如,许多网络服务器使用操作系统的 发送文件() 系统调用将文件直接从文件系统异步发送到网络接口。存储在数据库中的图像不会从这种优化中受益。
- 像网络服务器等,不需要特殊的编码或处理来访问文件系统中的图像
- 在图像和元数据之间的事务完整性很重要的情况下,数据库胜出。
- 管理数据库元数据和文件系统数据之间的完整性更加复杂
- 很难(在 Web 应用程序的上下文中)保证数据已刷新到文件系统上的磁盘
与大多数问题一样,它并不像听起来那么简单。在某些情况下,将图像存储在数据库中是有意义的。
- 您正在存储动态变化的图像,例如发票,您想像2007年1月1日一样获取发票吗?
- 政府希望你保持6年的历史
- 存储在数据库中的图像不需要不同的备份策略。存储在文件系统上的图像
- 如果图像位于数据库中,则更容易控制对图像的访问。空闲管理员可以访问磁盘上的任何文件夹。需要真正有决心的管理员才能在数据库中窥探以提取图像
另一方面也存在相关问题
- 需要其他代码来提取和流式传输图像
- 延迟可能比直接文件访问速度慢
- 数据库服务器负载较重
文件存储。Facebook 工程师对此进行了精彩的讨论。一个要点是了解目录中文件的实际限制。
这可能有点遥远,但如果您正在使用(或计划使用)SQL Server 2008,我建议您看看新的 文件流 数据类型。
FileStream 解决了在数据库中存储文件的大部分问题:
- Blob 实际上作为文件存储在文件夹中。
- 可以使用以下方式访问 Blob 任何一个 数据库连接 或者 在文件系统上。
- 备份是集成的。
- 迁移“正常”。
然而,SQL 的“透明数据加密”不会加密 FileStream 对象,因此如果考虑到这一点,您最好将它们存储为 varbinary。
来自 MSDN 文章:
Transact-SQL 语句可以插入、更新、查询、搜索和备份 FILESTREAM 数据。Win32 文件系统接口提供对数据的流式访问。
FILESTREAM 使用 NT 系统缓存来缓存文件数据。这有助于减少 FILESTREAM 数据可能对数据库引擎性能产生的任何影响。不使用SQL Server缓冲池;因此,该内存可用于查询处理。
数据库中的文件路径是 确实 要走的路 - 我从拥有 TB 图像的客户那里听到了一个又一个的故事,试图在数据库中存储大量图像变成了一场噩梦 - 仅对性能的影响就太大了。
根据我的经验,有时最简单的解决方案是 根据主键命名图像. 。因此很容易找到属于特定记录的图像,反之亦然。但同时你没有存储 任何事物 关于数据库中的图像。
这里的技巧是不要成为狂热分子。
这里需要注意的一件事是,专业文件系统阵营中没有人列出特定的文件系统。这是否意味着从 FAT16 到 ZFS 的所有内容都可以轻松击败所有数据库?
不。
事实上,许多数据库击败了许多文件系统,即使我们只谈论原始速度。
正确的行动方针是针对您的具体场景做出正确的决定,为此,您需要一些数字和一些用例估计。
在必须保证引用完整性和 ACID 合规性的地方,需要将图像存储在数据库中。
您无法以事务方式保证图像和数据库中存储的有关该图像的元数据引用同一文件。换句话说,不可能保证文件系统上的文件仅在与元数据相同的时间和同一事务中被更改。
正如其他人所说,SQL 2008 附带了一个 Filestream 类型,它允许您将文件名或标识符作为指针存储在数据库中,并自动将图像存储在文件系统上,这是一个很好的场景。
如果您使用的是较旧的数据库,那么我想说,如果您将其存储为 blob 数据,那么您实际上不会以搜索功能的方式从数据库中获取任何内容,所以这可能是最好的在文件系统上存储地址,并以这种方式存储图像。
这样,您还可以节省文件系统上的空间,因为您只会节省文件系统上确切的空间量,甚至是压缩的空间。
此外,您可以决定使用某些结构或元素进行保存,这些结构或元素允许您在没有任何数据库命中的情况下浏览文件系统中的原始图像,或者将文件批量传输到另一个系统、硬盘驱动器、S3 或其他场景 - 更新位置您的程序,但保留结构,在尝试增加存储时,再次尝试将图像从数据库中取出时不会受到太大影响。
也许,它还允许您根据经常点击的图像网址将一些缓存元素放入您的网络引擎/程序中,这样您也可以在那里保存自己。
不经常编辑的小型静态图像(不超过几兆)应存储在数据库中。这种方法有几个好处,包括更容易移植(图像与数据库一起传输)、更容易备份/恢复(图像与数据库一起备份)和更好的可扩展性(包含数千个小缩略图文件的文件系统文件夹听起来像是可扩展性噩梦)我)。
从数据库提供图像很容易,只需实现一个 http 处理程序,该处理程序将从数据库服务器返回的字节数组作为二进制流提供服务。
这是关于该主题的有趣白皮书。
答案是“这取决于”。当然,这将取决于数据库服务器及其BLOB存储的方法。它还取决于存储在 blob 中的数据类型以及如何访问该数据。
使用数据库作为存储机制,可以有效地存储和传递较小尺寸的文件。较大的文件可能最好使用文件系统存储,特别是如果它们经常被修改/更新。(blob 碎片成为性能方面的一个问题。)
还有一点需要记住。支持使用数据库来存储 blob 的原因之一是 ACID 合规性。然而,测试人员在白皮书中使用的方法(SQL Server 的批量日志选项)使 SQL Server 吞吐量翻倍,有效地将 ACID 中的“D”更改为“d”,因为 blob 数据未使用事务的初始写入。因此,如果完全符合 ACID 是系统的重要要求,则在将文件 I/O 与数据库 Blob I/O 进行比较时,将数据库写入的 SQL Server 吞吐量数字减半。
我还没有看到有人提到但绝对值得注意的一件事是,在大多数文件系统中存储大量图像也存在相关问题。例如,如果您采用上述方法并在主键之后命名每个图像文件,那么在大多数文件系统上,如果您尝试将所有图像放入一个大目录中,一旦达到大量图像(例如数十万或数百万)。
曾经常见的解决方案是将它们散列到平衡的子目录树中。
没有人提到的是数据库保证原子操作、事务完整性并处理并发性。即使是文件系统也无法实现引用完整性 - 那么您如何知道您的文件名确实仍然正确?
如果您的图像位于文件系统中,并且在您编写新版本甚至删除该文件时有人正在读取该文件 - 会发生什么?
我们使用 blob 是因为它们也更容易管理(备份、复制、传输)。它们对我们来说效果很好。
在数据库中仅存储图像的文件路径的问题是无法再强制数据库的完整性。
如果文件路径指向的实际图像变得不可用,则数据库会无意中出现完整性错误。
鉴于图像是正在寻找的实际数据,并且可以在一个集成数据库中更轻松地管理它们(图像不会突然消失),而不必与某种文件系统交互(如果文件系统是独立访问的)图像可能会突然“消失”),我会直接将它们存储为 BLOB 等。
在我曾经工作过的一家公司,我们在 Oracle 8i(后来是 9i)数据库中存储了 1.55 亿张图像。价值 7.5TB。
通常,我强烈反对采用基础设施中最昂贵和最难扩展的部分(数据库)并将所有负载放入其中。另一方面:它极大地简化了备份策略,特别是当您拥有多个 Web 服务器并且需要以某种方式保持数据同步时。
与大多数其他事情一样,这取决于预期的规模和预算。
我们已经实现了一个文档成像系统,它将所有图像存储在 SQL2005 blob 字段中。目前有数百 GB,我们看到响应时间非常好,并且性能下降很少或没有。此外,为了遵守法规,我们有一个中间件层,可以将新发布的文档存档到光学点唱机系统中,该系统将它们作为标准 NTFS 文件系统公开。
我们对结果非常满意,特别是在以下方面:
- 易于复制和备份
- 能够轻松实施文档版本控制系统
如果这是基于 Web 的应用程序,那么将图像存储在第三方存储交付网络(例如 Amazon 的 S3 或 Nirvanix 平台)上可能会有优势。
如果您没有使用 SQL Server 2008,并且您有充分的理由将特定图像文件放入数据库中,那么您可以采用“两者”方法,将文件系统用作临时缓存,并将数据库用作主存储库。
例如,您的业务逻辑可以在提供图像文件之前检查光盘上是否存在图像文件,并在必要时从数据库中检索。这为您带来了多个 Web 服务器的功能和更少的同步问题。
我不确定这在多大程度上是一个“现实世界”的例子,但我目前有一个应用程序,它存储集换式卡牌游戏的详细信息,包括卡牌的图像。迄今为止,数据库的记录数仅为 2851 条记录,但考虑到某些卡片已多次发布且具有替代艺术品,实际上,按大小扫描艺术品的“主方块”然后动态扫描会更有效。根据要求生成卡片的边框和其他效果。
该图像库的原始创建者创建了一个数据访问类,该类根据请求呈现图像,并且对于查看和单独的卡片来说它的速度相当快。
当新卡发布时,这也简化了部署/更新,而不是压缩整个图像文件夹并将其发送到管道中并确保创建正确的文件夹结构,我只需更新数据库并让用户再次下载它。目前大小高达 56MB,这不太好,但我正在为未来的版本开发增量更新功能。此外,该应用程序还有一个“无图像”版本,允许通过拨号的用户无下载延迟地获取该应用程序。
该解决方案迄今为止效果很好,因为应用程序本身被定位为桌面上的单个实例。有一个网站,所有这些数据都被存档以供在线访问,但我绝不会为此使用相同的解决方案。我同意文件访问会更好,因为它可以更好地适应图像请求的频率和数量。
希望这不是太多废话,但我看到了这个主题,并想从一个相对成功的中小型应用程序中提供一些我的见解。
SQL Server 2008 提供了一个兼具两全其美的解决方案: 文件流数据类型.
像普通表一样管理它并具有文件系统的性能。
这取决于您要存储的图像数量及其大小。我过去曾经使用数据库来存储图像,并且我的经验相当不错。
IMO,使用数据库存储图像的优点是,
A。你不需要 FS 结构来保存你的图像
B.当要存储更多数量的项目时,数据库索引的性能优于 FS 树
C。智能调整的数据库在缓存查询结果方面表现出色
D .备份很简单。如果您设置了复制并且内容是从靠近用户的服务器传送的,它也可以很好地工作。在这种情况下,不需要显式同步。
如果您的图像很小(例如< 64k)并且数据库的存储引擎支持内联(记录中)BLOB,则它会进一步提高性能,因为不需要间接(实现引用局部性)。
当您处理少量大尺寸图像时,存储图像可能不是一个好主意。在数据库中存储图像的另一个问题是,创建、修改日期等元数据必须由应用程序处理。
我最近创建了一个 PHP/MySQL 应用程序,它将 PDF/Word 文件存储在 MySQL 表中(到目前为止每个文件有 40MB)。
优点:
- 上传的文件与其他所有内容一起复制到备份服务器,不需要单独的备份策略(安心)。
- 设置 Web 服务器稍微简单一些,因为我不需要 uploads/ 文件夹并告诉我的所有应用程序它在哪里。
- 我可以使用事务进行编辑以提高数据完整性 - 我不必担心孤立和丢失的文件
缺点:
- mysqldump 现在需要很长的时间,因为其中一个表中有 500MB 的文件数据。
- 总体而言,与文件系统相比,内存/CPU 效率不高
我认为我的实施是成功的,它满足了备份要求并简化了项目的布局。对于 20-30 名使用该应用程序的人来说,性能还不错。
根据我的经验,我必须处理这两种情况:图像存储在数据库中,图像存储在文件系统中,路径存储在 db 中。
第一个解决方案是数据库中的图像,有点“干净”,因为您的数据访问层只需处理数据库对象;但这仅在您必须处理少量数据时才有用。
显然,处理二进制大对象时数据库访问性能正在下降,并且数据库维度会增长很多,再次导致性能损失......通常数据库空间比文件系统空间贵得多。
另一方面,将大型二进制对象存储在文件系统中将导致您的备份计划必须同时考虑数据库和文件系统,这对于某些系统来说可能是一个问题。
使用文件系统的另一个原因是当您必须与第三方访问共享图像数据(或声音、视频等)时:如今,我正在开发一个网络应用程序,该应用程序使用必须从我的网络场“外部”访问的图像,这样数据库访问检索二进制数据是根本不可能的。因此,有时设计考虑因素也会促使您做出选择。
在做出此选择时,还要考虑在访问二进制对象时是否必须处理权限和身份验证:当数据存储在数据库中时,这些要求通常可以更简单地解决。
我曾经开发过一个图像处理应用程序。我们将上传的图像存储在类似 /images/[今天的日期]/[id 号] 的目录中。但我们还从图像中提取元数据(exif 数据)并将其与时间戳等一起存储在数据库中。
在之前的项目中,我将图像存储在文件系统上,这导致了备份、复制以及文件系统与数据库不同步等方面的很多麻烦。
在我最新的项目中,我将图像存储在数据库中,并将它们缓存在文件系统上,而且效果非常好。到目前为止我还没有遇到任何问题。
其次是文件路径的建议。我参与过几个需要管理大型资产集合的项目,任何将数据直接存储在数据库中的尝试都会导致长期的痛苦和挫败。
我能想到的关于将它们存储在数据库中的唯一真正的“优点”是易于单个图像资产的潜力。如果没有可供使用的文件路径,并且所有图像都直接从数据库中流出,则用户不会发现他们不应访问的文件。
不过,这似乎可以通过中间脚本从网络无法访问的文件存储中提取数据来更好地解决。所以数据库存储并不是真正必要的。
坊间流传的说法是,除非您是一个数据库供应商,试图证明您的数据库可以做到这一点(例如,微软吹嘘 Terraserver 在 SQL Server 中存储了无数图像),否则这不是一个好主意。当替代方案 - 将图像存储在文件服务器上和数据库中的路径如此容易时,为什么还要麻烦呢?Blob 字段有点像 SUV 的越野功能 - 大多数人不使用它们,那些使用它们的人通常会遇到麻烦,还有一些人使用它们,但只是为了好玩。
将图像存储在数据库中仍然意味着图像数据最终会存储在文件系统中的某个位置,但会被隐藏,因此您无法直接访问它。
+ves:
- 数据库完整性
- 它易于管理,因为您不必担心在添加或删除图像时保持文件系统同步
-ves:
- 性能损失——数据库查找通常比文件系统查找慢
- 您无法直接编辑图像(裁剪、调整大小)
这两种方法都很常见并且被实践。看看优点和缺点。无论哪种方式,你都必须考虑如何克服缺点。存储在数据库中通常意味着调整数据库参数并实现某种缓存。使用文件系统需要您找到某种方法来保持文件系统+数据库同步。