2011-12-05 70 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

您想要存儲數據並將其串流化。這兩個要求並不一致。特別是在你插入的情況下。 –

相關問題