5

在 mysqlMyISAM表中,我有一个列类型mediumblob并将捕获的图像存储为 blob 数据。我得到了一些有趣且有问题的图像。一些图像是gradually losing数据。

Field          type  
--------------------------
image         mediumblob

my.ini最大允许数据包大小集max_allowed_packet = 8M

图像1 图2 图3

这就是问题

C#应用程序从服务器获取数据时,这种图像每次都会丢失随机大小的数据。我在图像数据中得到了10-12这样的坏图像。100000+

这种行为的原因可能是什么?任何人都有任何想法/解决方案如何解决/避免这个问题。

更新 1:
从 PictureBox 中读取字节

MemoryStream ms = new MemoryStream();
byte[] ret = null;

try
{
     picturebox.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
     byte[] Data = new byte[ms.Length];
     ms.Read(Data, 0, (int)ms.Length);
     ret = byteData;
     ms.Close();
 }         
 

将字节数组作为中等 blob 数据保存到数据库中。从数据库中检索数据时,我正在转换阅读器数据:

byte[] Data = (byte[])reader["Image"];
4

5 回答 5

6

首先,正如 Sarke 提到的,将文件内容存储在数据库中并不是最好的主意(文件元数据是完全不同的故事。

为什么?

  1. 性能:在大多数情况下,操作系统文件缓存将优于 DBMS 中内置的任何内容。
  2. 灾难恢复:在失败时丢失所有/大多数文件的几率比文件系统要高得多,而且恢复要困难得多
  3. 扩展:如果您超出单个服务器的容量,则添加应用程序级分片是微不足道的,并且不会降低性能。多服务器数据库设置更“痛苦”
  4. 多种解决方案/易于迁移:有大量用于大型文件集合存储的硬件和软件解决方案,它们之间的迁移比 DBMS 之间的迁移简单得多

我存储了近 200 万张图像,这些图像存储在一个简单的文件夹结构中:/xx/yy/filename,其中文件名 = 文件的 md5(+ 发生哈希冲突时的可选编号),xx = md5 的前 2 个字符,yy = md5 的第 3 和第 4 个字符. 它工作得很好,我不应该在很长一段时间内得到任何与 FS 相关的减速(至少 2 个数量级)。

回到你的问题,有3个选项

  1. 这些文件永远不会正确保存到数据库中。上传照片的应用程序可能有问题或图像太大。您max_allowed_packet将图像大小限制为 ~8 MB,mediub_blob最多可存储 16 MB。为了排除这一点,将其增加到max_allowed_packet32 MB 并进行测试。您需要确保在任何时候没有图像超过此大小,并确保应用程序在上传照片时正确完成工作。如果您可以找到上传并显示正常的图像(来自 DB!),但后来却没有,那么这不是原因。
  2. 文件在更新过程中损坏 - 如果有任何东西以任何方式更新照片,那么即使原始文件很好,更新的文件也可能不是 - 例如,它可能超过第 1 点的大小限制。
  3. (最不可能的)如果文件在没有损坏的情况下被存储和更新,那么它在存储时被损坏->没有报告 MySQL 错误(这不会被忽视)我会查看服务器硬件。
于 2012-06-15T17:30:03.160 回答
4

罪魁祸首是 MyISAM 存储类型。

我们使用 InnoDB 存储存储了 100 万张图像并进行了压力测试,我们得到了正确的结果。要么文件被正确检索,要么根本没有被检索(小于 0.01%),因为 InnoDB 是酸兼容的。

当我们转移到 MyISAM 时,丢失数据的失败率增加到 20%,与您的情况相同。原因是,MyISAM 使用表锁,所以在写入过程中,整个表都被锁定,并且在超时的情况下,它确实会覆盖导致数据丢失的某些内容。

我们现在已经把所有东西都转移到了 MS SQL,因为 InnoDB 性能很好,但它仍然从不重用已删除的文件空间,所以 InnoDB 不断地增长。MS SQL express 有 10gb 的限制,所以我们创建了 4-8gb 的页面并在那里存储 blob。而且我们有自己的自定义复制,可以在具有相同配置的网络上的三台服务器上复制文件。

将文件存储在磁盘上是不好的,原因有很多,每个人都在说文件系统是为高性能而设计的,可以存储数百万个文件,这是不正确的,当你有超过 10 万个文件时,驱动器无法更快地执行。它们在处理一个大文件然后处理 1000 个小文件时表现良好。目前我们正在存储 1000 万个文件并将其存储在 db 中更有意义,因为 db 对查询进行了优化并进行了良好的缓存。您可以在http://akashkava.com/blog/127/huge-file-storage-in-database-instead-of-file-system/阅读更多内容

这就是发明 MongoDb、Hadoop、Azure Blob Store、Haystack 和 Amazon S3 的确切原因。

于 2012-06-22T07:35:48.487 回答
2

我认为您首先需要弄清楚是您的应用程序还是某些外部进程(备份/恢复?)更改了这些数据。实际上,如果文件应该保持不变,我认为您的应用程序需要更新此图片(即使用相同的数据更新字段)的理由很少。

一旦您发现应用程序的哪些部分更新了此字段,您可能需要发布一些代码以查看是否没有发生转换、转义或其他任何事情。

如果像我假设的那样,这种更新永远不会发生,那么BEFORE UPDATE在表上设置触发器将使您能够准确地知道问题何时发生,并可能有助于识别可能的模式。比较OLDNEW值并在日志表中记录尽可能多的相关可用数据 - 请注意,比较大型 BLOB 可能会成为性能杀手,请密切关注您的性能。

于 2012-06-16T02:49:15.750 回答
1

我的公司选择将图像存储在数据库之外。我们注意到,与您使用的 Blob 一样,Blob 很容易出现损坏和性能问题。我们在 MSSQL、Sybase 和 Faircom 中看到了同样的问题。

每当应用程序需要访问图像时,它都需要访问可以找到该图像的网络(或基于 Web)的存储。然后数据只存储图像的路径。

由于图像是文件系统中某处的平面文件,因此如果需要更新记录(即添加注释以描述图像),则其自身的图像不会重新编译到 blob 中,并且没有机会它被破坏了。

于 2012-06-19T13:00:09.350 回答
0

您使用什么 API 从数据库中获取数据?给我们一些获取数据的代码。

通常,BLOB 是使用某种“流”从数据库中读取的,因此如果您使用它,可能需要切换到比 ADO.NET 更强大的东西。

此页面可能有用:http ://dev.mysql.com/doc/refman/5.5/en/connector-net-programming-blob.html

于 2012-06-16T12:36:44.883 回答