2011-12-05 68 views
3

我发现了很多关于如何使用CommandBehavior.SequentialAccess将BLOB选择为流的信息。如何在插入时将BLOB流式传输到VARBINARY(MAX)

我想插入BLOB(避免将BLOB缓存为内存中的字节数组),我找不到任何示例。我在UPDATE T-SQL语句中发现了一些提及.WRITE (expression,@Offset, @Length)语法的文档,该语句与VARBINARY(MAX)兼容。所以,我正在考虑编写一个可以采用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

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

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(); 
      } 
     } 
    } 
} 
+0

SqlFileStream在SQL DB上有更好的性能和更少的负载,但需要SQL2008或更高版本。 http://msdn.microsoft.com/en-us/library/system.data.sqltypes.sqlfilestream.aspx – Bengie

+0

谢谢@Bengie,这很好,但我需要将数据内联存储在数据库中,而不是在FILESTREAM中。 –

回答

1

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

+0

谢谢@Hasan。这很有趣,但不直接帮助我;对于我的要求,我想保留数据库中的BLOB。 RBS团队博客确实提到除了示例FileStoreLibrary BlobStore之外,他们还编写了支持FILESTREAM的BlobStore。我正在下载Add On和示例代码,以便检查它们是否流到FileStream(我怀疑它,因为我期望它们使用Win32直接访问FILESTREAM。) –

+0

因此,我已经查看RBS代码和FileStream BlobStore的SQL,并且有一个内联存储数据的选项(即,在VARBINARY(MAX)而不是FILESTREAM中),但是当它设置为store_inline = true时,RBS不会流(这正是我想要的)。奇怪的是,他们将BLOB分成最多25个块,作为sproc的单独参数,然后将sproc(rbs_fs_sp_store_blob_params)中的数据一起写入varbinary(max)并一次插入。 –

+0

您想要存储数据并将其串流化。这两个要求并不一致。特别是在你插入的情况下。 –

相关问题