【问题标题】:Memory effective way to read BLOB data in C#/SQL 2005在 C#/SQL 2005 中读取 BLOB 数据的内存有效方法
【发布时间】:2009-09-28 15:50:02
【问题描述】:

使用 C# 3.5 读取 SQL 2005 图像字段最节省内存的方法是什么?

现在我有一个(byte[])cm.ExecuteScalar("...")

如果我不能将所有字段内容读入内存,那就太好了。

【问题讨论】:

    标签: sql sql-server sql-server-2005 tsql


    【解决方案1】:

    请参阅此出色的 article here 或此 blog post 以获得详细的说明。

    基本上,您需要使用 SqlDataReader 并在创建它时为其指定 SequentialAccess - 然后您可以从数据库中读取(或写入)BLOB,以最适合您的大小。

    基本上是这样的:

    SqlDataReader myReader = getEmp.ExecuteReader(CommandBehavior.SequentialAccess);
    
    while (myReader.Read())
    {
       int startIndex = 0;
    
       // Read the bytes into outbyte[] and retain the number of bytes returned.
       retval = myReader.GetBytes(1, startIndex, outbyte, 0, bufferSize);
    
       // Continue reading and writing while there are bytes beyond the size of the buffer.
       while (retval == bufferSize)
       {
          // write the buffer to the output, e.g. a file
          ....
    
          // Reposition the start index to the end of the last buffer and fill the buffer.
          startIndex += bufferSize;
          retval = myReader.GetBytes(1, startIndex, outbyte, 0, bufferSize);
       }
    
       // write the last buffer to the output, e.g. a file
       ....
    }
    
    // Close the reader and the connection.
    myReader.Close();
    

    马克

    【讨论】:

    • 这里面有一些重要的问题;如果最后一个块不是完整的缓冲区加载,则您不会增加数据偏移量,并且不会处理最终缓冲区...
    • 我认为数据偏移量正在增加(startIndex += bufferSize) - 不是吗?是的 - 这里没有显示最后一个不完整的缓冲区 - 这是我链接到的较长文章的摘录,以说明机制中最重要的部分 - 它不是完整的工作代码跨度>
    • 好的;偏移量上的“我的坏”;-p
    • 粗心大意的注意事项:在没有对阅读器设置 CommandBehavior.SequentialAccess 的情况下执行此操作可能会导致 OutOfMemoryException,例如,如果从 2MB 文件中以 1K 的增量提取数据,总共会调用 2000 次 GetBytes()。查看 GetBytes 的实现,看起来它每次都将整个 Blob 值读取到一个数组中,然后再将请求的字节复制到您的数组中。在 1k 块中提取 2MB 的值,你的内存会很快被 2MB 的临时数组填满! (其中 2000 个,除非 GC 及时清理它们) - 因此出现错误。
    【解决方案2】:

    这里的技巧是在顺序模式下使用 ExecuteReader,并从IDataReader 读取数据。 Here's a version for CLOBs - BLOB 几乎相同,但具有 byte[]GetBytes(...)

    类似:

    using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
    {
        byte[] buffer = new byte[8040]; // or some multiple (sql server page size)
        while (reader.Read()) // each row
        {
            long dataOffset = 0, read;
            while ((read = reader.GetBytes(
                colIndex, dataOffset, buffer, 0, buffer.Length)) > 0)
            {
                // TODO: process "read"-many bytes from "buffer"
                dataOffset += read;
            }
        }
    }
    

    【讨论】:

    • 再次,如果有人看到这个答案并错过了我上面的评论:你必须设置 CommandBehavior.SequentialAccess。如果你不这样做,它可能看起来可以工作一段时间,但你会用临时 blob 大小的字节数组乱扔你的进程,并最终会在更大的 blob 提取时得到 OutOfMemoryException!
    • @Tao - 但在两个答案中,我们都记得添加 ;p
    • 是的,我刚刚在我们的应用程序中发现了一些代码,但有人遗漏了它 - 这造成了很大的混乱。我不是在批评答案,只是在我的情况下添加一些对某人有用的信息。这是我的热门搜索结果之一,也是唯一一个我可以添加此有用信息以供将来参考的结果。我认为把它放在那里很重要的原因是,如果没有“SequentialAccess”,它看起来就像它正在工作......我猜负责的开发人员对它被正确实施感到满意。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-13
    • 1970-01-01
    • 1970-01-01
    • 2011-10-10
    • 2017-04-27
    • 1970-01-01
    • 2011-07-29
    相关资源
    最近更新 更多