ADO.Netバッファ挿入大型データ

5635 ワード

ADO.Netバッファ挿入大型データ
Database, C#, ASP.NET
2004-8-9 | 16:58
データベース内のフィールドタイプに応じて、文字列値またはバイト配列を持つフィールドを挿入または更新することで、データベースにバイナリオブジェクト(BLOB)を書き込むことができます.ただし、BLOBはかなり大きいため、単一の値として書き込む際に大量のシステムメモリを使用し、アプリケーションのパフォーマンスを低下させる可能性があります.BLOB値を書き込むときに使用するメモリ量を減らすには、通常、BLOBを「ブロック領域」としてデータベースに書き込む.この方法でBLOBをデータベースに書き込むプロセスは、データベースの機能に依存します.次の例では、BLOBをSQLサーバにブロック形式で書き込む方法を示します.この例では、NorthwindデータベースのEmployeesテーブルに、BLOBである従業員画像を含む新しいレコードを追加します.この例では、SQL ServerのUPDATEXT関数を使用して、新しく追加した従業員の画像を指定したサイズのブロック領域でPhotoフィールドに書き込みます.UPDATETEXT関数には、更新されたBLOBフィールドへのポインタが必要です.この例では、新入社員のレコードを追加すると、SQL Server TEXTPTR関数が呼び出され、新しいレコードのPhotoフィールドへのポインタが返されます.返されたポインタ値は出力パラメータとして返されます.例のコードはこのポインタを保持し、データブロック領域を追加するときにUPDATEXTに渡します.次の例では、新入社員レコードを挿入し、Photoフィールドへのポインタを保持するためのTransact-SQLが表示されます(@Identityおよび@Pointerは、SqlCommandの出力パラメータとして識別されます).
INSERT INTO Employees (LastName, FirstName, Title, HireDate, ReportsTo, Photo) 

  Values(@LastName, @FirstName, @Title, @HireDate, @ReportsTo, 0x0)

SELECT @Identity = SCOPE_IDENTITY()

SELECT @Pointer = TEXTPTR(Photo) FROM Employees WHERE EmployeeID = @Identity
初期値0x0(空)がPhotoフィールドに挿入されていることに注意してください.これにより、新しく挿入されたレコードのPhotoフィールドのポインタ値が取得されることを保証します.ただし、空の値は追加のブロック領域には影響しません.新しい挿入レコードのPhotoフィールドへのポインタを保持した後、例は、SQLサーバのUPDATEXT関数を使用してBLOBフィールドにデータブロック領域を追加することができます.UPDATEXT関数では、フィールド識別子(Employees.Photo)、BLOBフィールドへのポインタ、BLOBに現在のブロック領域が書き込まれている位置を示すオフセット値、および追加するデータブロック領域として入力されます.次のコード例は、UPDATEXT関数のシンタックスを示します(ここで、@Pointer@Offset 、および@Bytesは、SqlCommandの入力パラメータとして識別されます).
UPDATETEXT Employees.Photo @Pointer @Offset 0 @Bytes
オフセット値は、アプリケーションのニーズに応じてメモリバッファのサイズによって決定されます.大きなバッファがBLOBに書き込まれる速度は速いが、より多くのシステムメモリが使用される.この例では、128バイトのバッファしか使用されません.最初のデータブロック領域に割り当てられたオフセット値は0であり、オフセット値は連続ブロック領域ごとのバッファサイズで増加します.この例では、指定したファイルパスから従業員の写真をブロック別に取得します.指定したバッファサイズに基づいて、各ブロック領域を1バイト配列に読み込みます.そして、バイト配列をSqlCommandの@Bytes入力パラメータの値に設定する.@Offsetパラメータ値を更新し、SqlCommandを実行すると、現在のバイトブロック領域が従業員レコードのPhotoフィールドに追加されます.[C#] using System; using System.Data; using System.Data.SqlClient; using System.IO; public class EmployeeData {   public static void Main()   {     DateTime hireDate = DateTime.Parse("4/27/98");     int newID  = AddEmployee("Smith", "John", "Sales Representative", hireDate, 5, "smith.bmp");     Console.WriteLine("New Employee added. EmployeeID = "+ newID);   }   public static int AddEmployee(string lastName, string firstName, string title, DateTime hireDate , int reportsTo, string photoFilePath)   {     SqlConnection nwindConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;");     SqlCommand addEmp  = new SqlCommand("INSERT INTO Employees (LastName, FirstName, Title, HireDate, ReportsTo, Photo) "+       "Values(@LastName, @FirstName, @Title, @HireDate, @ReportsTo, 0x0);"+       "SELECT @Identity = SCOPE_IDENTITY();"+       "SELECT @Pointer = TEXTPTR(Photo) FROM Employees WHERE EmployeeID = @Identity", nwindConn);     addEmp.Parameters.Add("@LastName",  SqlDbType.NVarChar, 20).Value = lastName;     addEmp.Parameters.Add("@FirstName", SqlDbType.NVarChar, 10).Value = firstName;     addEmp.Parameters.Add("@Title",     SqlDbType.NVarChar, 30).Value = title;     addEmp.Parameters.Add("@HireDate",  SqlDbType.DateTime).Value     = hireDate;     addEmp.Parameters.Add("@ReportsTo", SqlDbType.Int).Value          = reportsTo;     SqlParameter idParm = addEmp.Parameters.Add("@Identity", SqlDbType.Int);     idParm.Direction = ParameterDirection.Output;     SqlParameter ptrParm = addEmp.Parameters.Add("@Pointer", SqlDbType.Binary, 16);     ptrParm.Direction = ParameterDirection.Output;     nwindConn.Open();     addEmp.ExecuteNonQuery();     int newEmpID = (int)idParm.Value;     StorePhoto(photoFilePath, (byte[])ptrParm.Value, nwindConn);     nwindConn.Close();     return newEmpID;   }   public static void StorePhoto(string fileName, byte[] pointer,  SqlConnection nwindConn)   {     int bufferLen = 128; //The size of the "chunks"of the image.     SqlCommand appendToPhoto = new SqlCommand("UPDATETEXT Employees.Photo @Pointer @Offset 0 @Bytes", nwindConn);     SqlParameter ptrParm  = appendToPhoto.Parameters.Add("@Pointer", SqlDbType.Binary, 16);     ptrParm.Value = pointer;     SqlParameter photoParm = appendToPhoto.Parameters.Add("@Bytes", SqlDbType.Image, bufferLen);     SqlParameter offsetParm = appendToPhoto.Parameters.Add("@Offset", SqlDbType.Int);     offsetParm.Value = 0;    //''''''''''''''''''''''''''''''''''    //Read the image in and write it to the database 128 (bufferLen) bytes at a time.    //Tune bufferLen for best performance. Larger values write faster, but    //use more system resources.     FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);     BinaryReader br = new BinaryReader(fs);     byte[] buffer = br.ReadBytes(bufferLen);     int offset_ctr = 0;     while (buffer.Length > 0)     {       photoParm.Value = buffer;       appendToPhoto.ExecuteNonQuery();       offset_ctr += bufferLen;       offsetParm.Value = offset_ctr;       buffer = br.ReadBytes(bufferLen);     }     br.Close();     fs.Close();   } }