【问题标题】:How can I stream a BLOB to VARBINARY(MAX) on INSERT如何在 INSERT 上将 BLOB 流式传输到 VARBINARY(MAX)
【发布时间】:2011-12-05 13:11:58
【问题描述】:

我找到了很多关于如何使用 CommandBehavior.SequentialAccess 选择 BLOB 作为流的信息。

我也想在插入时流式传输 BLOB(以避免将 BLOB 缓存为内存中的字节数组),但我找不到任何示例。我发现一些文档在UPDATE T-SQL 语句中提到了与VARBINARY(MAX) 兼容的.WRITE (expression,@Offset, @Length) 语法。所以,我正在考虑编写一个类,它可以使用Stream 并使用连续的 UPDATE (.WRITE) 语句将其分块到数据库中。这是执行此操作的正确方法,还是有更好的方法?

UPDATE.WRITE 的链接:

http://msdn.microsoft.com/en-us/library/ms178158(SQL.100).aspx

http://msdn.microsoft.com/en-us/library/ms177523(v=SQL.100).aspx

使用 CommandBehavior.SequentialAccess 选择 BLOB 的链接:

http://msdn.microsoft.com/en-us/library/87z0hy49.aspx

Memory effective way to read BLOB data in C#/SQL 2005

Getting binary data using SqlDataReader

How to make streams from BLOBs available in plain old C# objects when using SqlDataReader?

Streaming VARBINARY data from SQL Server in C#

这是使用 .Write 语法的 POC:

DDL:

create database BlobTest
go
use blobtest
go

create table Blob
(
    Id bigint not null primary key identity(1,1),
    Data varbinary(max) not null default(0x)
)

C#:

using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main()
        {
            string pathToBigFile = "C:\\bigfile.big";
            int optimumBufferSizeForSql = 8040; //See https://stackoverflow.com/questions/5629991/how-can-i-generate-an-insert-script-for-a-table-with-a-varbinarymax-field

            long newBlobId = InitialiseNewBlobInSqlServer();

            using (Stream stream = new FileStream(  pathToBigFile, 
                                                    FileMode.Open, 
                                                    FileAccess.Read, 
                                                    FileShare.ReadWrite))
            {
                byte[] buffer = new byte[optimumBufferSizeForSql];

                while(true)
                {
                    int numberBytesRead = stream.Read(buffer, 0, optimumBufferSizeForSql);

                    if (numberBytesRead == 0)
                    {
                        //Done
                        break;
                    }

                    WriteBufferToSqlServer(
                        numberBytesRead == optimumBufferSizeForSql ? buffer : buffer.Take(numberBytesRead).ToArray(),
                        newBlobId);
                }
            }
        }

        static long InitialiseNewBlobInSqlServer()
        {
            using (SqlConnection conn = new SqlConnection("Data Source=localhost; Initial Catalog=BlobTest; Integrated Security=SSPI;"))
            using (SqlCommand command = new SqlCommand())
            {
                command.Connection = conn;
                command.CommandType = CommandType.Text;
                command.CommandText = "Insert into blob (Data) values (0x); select convert(bigint,Scope_identity());";

                conn.Open();
                return (long) command.ExecuteScalar();
            }
        }

        static void WriteBufferToSqlServer(byte[] data, long blobId)
        {
            using (SqlConnection conn = new SqlConnection("Data Source=localhost; Initial Catalog=BlobTest; Integrated Security=SSPI;"))
            using (SqlCommand command = new SqlCommand())
            {
                command.Connection = conn;
                command.CommandType = CommandType.Text;
                command.Parameters.AddWithValue("@id", blobId);
                command.Parameters.AddWithValue("@data", data);
                command.CommandText = "Update Blob set Data.Write(@data, null, null) where Id = @id;";

                conn.Open();
                command.ExecuteNonQuery();
            }
        }
    }
}

【问题讨论】:

  • SqlFileStream 性能更好,对 SQL DB 的负载更少,但需要 SQL2008 或更高版本。 msdn.microsoft.com/en-us/library/…
  • 谢谢@Bengie,这很好,但我需要将数据内联存储在数据库中而不是文件流中。

标签: c# sql-server-2008


【解决方案1】:

您应该使用 SQL Server 的 RBS 接口来处理 blob。

【讨论】:

  • 谢谢@Hasan。这很有趣,但不能直接帮助我;对于我的要求,我想将 BLOB 保留在数据库中。 RBS 团队博客确实提到,除了示例 FileStoreLibrary BlobStore 之外,他们还编写了一个支持 FILESTREAM 的 BlobStore。我正在下载 Add On 和示例代码,以便检查它们是否流式传输到 FileStream(我对此表示怀疑,因为我希望他们使用 Win32 直接访问 FILESTREAM。)
  • 所以,我查看了 FileStream BlobStore 的 RBS 代码和 SQL,并且可以选择内联存储数据(即在 VARBINARY(MAX) 而不是 FILESTREAM 中)但是当它设置为 store_inline = true 时,RBS 不会将数据流式传输(这是我想要的)。奇怪的是,他们将 BLOB 分解为最多 25 个块,作为 sproc 的单独参数,然后。写sproc (rbs_fs_sp_store_blob_params) 中的数据一起放入 varbinary(max) 并一次性插入。
  • 您希望将数据存储在行中并流式传输。这两个要求不能很好地结合在一起。特别是在您的插入情况下。
  • 为什么“尤其是在您的插入情况下”,即插入和选择之间的根本区别是什么?
  • @DanielJamesBryars 的根本区别在于,在插入时,您在 db 中创建了一行,而在读取该行期间该行已经存在。您可以花一年时间根据自己的意愿将其流式传输;不会打扰数据库,但在插入时必须尽可能快。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-26
  • 2015-03-15
  • 2012-04-14
  • 2021-06-11
  • 1970-01-01
  • 2012-08-26
  • 1970-01-01
相关资源
最近更新 更多