2015-10-28 60 views
14

Tôi đang cố gắng sử dụng Fluent NHibernate để di chuyển cơ sở dữ liệu cần một số cơ sở dữ liệu 'mát xa'. Cơ sở dữ liệu nguồn là một cơ sở dữ liệu MS Access và bảng hiện tại mà tôi đang mắc kẹt là một với một trường đối tượng OLE. Cơ sở dữ liệu đích là cơ sở dữ liệu MS SQL Server Express.NHibernate OutOfMemoryException truy vấn byte lớn []

Trong đơn vị tôi chỉ đơn giản có lĩnh vực này được định nghĩa là một byte[] Tuy nhiên khi tải tuy nhiên ngay cả khi chỉ tải mà lĩnh vực duy nhất cho một hồ sơ duy nhất tôi đã chạm System.OutOfMemoryException

byte[] test = aSession.Query<Entities.Access.Revision>().Where(x => x.Id == 5590).Select(x => x.FileData).SingleOrDefault<byte[]>(); 

sau đó tôi đã cố gắng thực hiện blob type listed here nhưng bây giờ khi chạy mà tôi nhận được một lỗi của:

"Unable to cast đối tượng của loại 'System.Byte []' gõ 'TestProg.DatabaseConverter.Entities.Blob'."}

Tôi không thể tưởng tượng được đối tượng Ole lớn hơn 100MB nhưng chưa thể kiểm tra. Có cách nào tốt bằng cách sử dụng Fluent NHibernate để sao chép này ra khỏi cơ sở dữ liệu một và lưu nó vào khác hoặc tôi sẽ cần phải xem xét các tùy chọn khác?

vòng bình thường của tôi để xử lý này là:

IList<Entities.Access.Revision> result; 
IList<int> recordIds = aSession.Query<Entities.Access.Revision>().Select(x => x.Id).ToList<int>(); 

foreach (int recordId in recordIds) 
{ 
    result = aSession.Query<Entities.Access.Revision>().Where(x => x.Id == recordId).ToList<Entities.Access.Revision>(); 
    Save(sqlDb, result); 
} 

Chức năng tiết kiệm chỉ là bản sao đặc tính từ một đến khác và đối với một số đơn vị được sử dụng để thao tác dữ liệu hoặc đưa ra phản hồi cho người sử dụng liên quan đến các vấn đề dữ liệu. Tôi đang sử dụng phiên không trạng thái cho cả hai cơ sở dữ liệu.

-

Từ các thử nghiệm tiếp theo, vật thể dường như đang treo trên khoảng 60-70mb. Tôi hiện đang thử nghiệm lấy dữ liệu với một OleDbDataReader bằng cách sử dụng GetBytes.

-

Cập nhật (ngày 24 tháng 11): Tôi chưa tìm cách để làm việc này với NHibernate. Tôi đã làm việc này với các đối tượng lệnh db thông thường. Tôi đã đặt mã cho chức năng tôi đã thực hiện dưới đây cho bất kỳ ai tò mò tìm thấy điều này. Đây là mã từ trình chuyển đổi cơ sở dữ liệu của tôi để các đối tượng có tiền tố là 'a' là các đối tượng cơ sở dữ liệu truy cập và 's' là các đối tượng sql.

public void MigrateBinaryField(int id, string tableName, string fieldName) 
{ 
    var aCmd = new OleDbCommand(String.Format(@"SELECT ID, {0} FROM {1} WHERE ID = {2}", fieldName, tableName, id), aConn); 

    using (var reader = aCmd.ExecuteReader(System.Data.CommandBehavior.SequentialAccess)) 
    { 
     while (reader.Read()) 
     { 
      if (reader[fieldName] == DBNull.Value) 
       return; 

      long read = 0; 
      long offset = 0; 

      // Can't .WRITE a NULL column so need to set an initial value 
      var sCmd = new SqlCommand(string.Format(@"UPDATE {0} SET {1} = @data WHERE OldId = @OldId", tableName, fieldName), sConn); 
      sCmd.Parameters.AddWithValue("@data", new byte[0]); 
      sCmd.Parameters.AddWithValue("@OldId", id); 
      sCmd.ExecuteNonQuery(); 

      // Incrementally store binary field to avoid OutOfMemoryException from having entire field loaded in memory 
      sCmd = new SqlCommand(string.Format(@"UPDATE {0} SET {1}.WRITE(@data, @offset, @len) WHERE OldId = @OldId", tableName, fieldName), sConn); 
      while ((read = reader.GetBytes(reader.GetOrdinal(fieldName), offset, buffer, 0, buffer.Length)) > 0) 
      { 
       sCmd.Parameters.Clear(); 
       sCmd.Parameters.AddWithValue("@data", buffer); 
       sCmd.Parameters.AddWithValue("@offset", offset); 
       sCmd.Parameters.AddWithValue("@len", read); 
       sCmd.Parameters.AddWithValue("@OldId", id); 

       sCmd.ExecuteNonQuery(); 

       offset += read; 
      }      
     } 
    } 
} 
+1

Heve bạn đã thử điều này? https://github.com/bittercoder/Lob – Najera

+0

@Najera Tôi đã chụp ảnh đó và không hoạt động. Tôi không thể nhớ các chi tiết cụ thể nhưng dường như nhớ lại vẫn thoát khỏi các ngoại lệ bộ nhớ. Nó đã được một chút trong khi bây giờ mặc dù vậy không phải 100% trên đó. –

+0

Bạn có thể cung cấp cho chúng tôi bản đồ bạn đã thực hiện không? – TedOnTheNet

Trả lời

0

Điều này nghe giống như kết quả tôi đã thấy khi sử dụng .NET trên các khuôn khổ khác.

Trình điều khiển cơ sở dữ liệu gốc bên dưới ADO.NET bên dưới NHibernate (hai "bên dưới" là cố ý ở đây) sẽ yêu cầu khối bộ nhớ đích được ghim không thể di chuyển trong bộ nhớ trong khi trình điều khiển điền vào nó. Vì bộ thu gom rác .NET có thể di chuyển các khối bộ nhớ một cách ngẫu nhiên trên một luồng riêng biệt để nén gọn đống, lớp cơ sở dữ liệu .NET của NHibernate phải tạo một khối bộ nhớ không được quản lý để nhận dữ liệu, giúp tăng gấp đôi số lượng bộ nhớ cần thiết để tải một bản ghi.

Ngoài ra, tôi chưa xác minh điểm tiếp theo này, nhưng NHibernate nên cố gắng lưu vào bộ đệm các bản ghi vì nó bỏ qua một số thao tác truy vấn cơ sở dữ liệu quan hệ. Điều này cho phép NHibernate thực hiện các yêu cầu cơ sở dữ liệu ít hơn, tối ưu cho các kích thước bản ghi nhỏ hơn, nhưng đòi hỏi nhiều bản ghi (bao gồm nhiều đốm màu) để vừa với bộ nhớ tại một thời điểm.

Là bước đầu tiên hướng tới độ phân giải, đảm bảo quá trình thực sự đang chạy máy hết bộ nhớ (hoặc nếu nó là 32 bit, hãy đảm bảo rằng nó đạt đến giới hạn 2 GB). Nếu vậy, cố gắng xác định đường cơ sở - nếu nó đang xử lý các bản ghi với nhiều kích cỡ blob, bộ nhớ tối thiểu và tối đa mà nó sử dụng là gì? Từ đó, bạn có thể ước tính số lượng bộ nhớ sẽ được yêu cầu cho bản ghi lớn đó (hoặc khối bộ nhớ cache có chứa bản ghi đó!)

Bộ nhớ vật lý 64 bit trở lên có thể là giải pháp brute-force, nếu bạn ' t đã chạy 64-bit, và nếu phần cứng lớn hơn thậm chí là một lựa chọn.

Một giải pháp khả thi khác là kiểm tra xem NHibernate có cài đặt cấu hình hoặc thuộc tính để lưu trữ dữ liệu hay không. Ví dụ: kiểm tra xem bạn có thể đặt thuộc tính giới hạn số lượng bản ghi được tải tại một thời điểm hay cho phép giới hạn bộ nhớ cache của nó ở một kích thước nhất định theo byte.

Một giải pháp hiệu quả hơn là sử dụng mã ADO.NET của bạn cho các đốm màu; đó có thể là giải pháp tốt nhất, đặc biệt là nếu bạn mong đợi các đốm màu lớn hơn so với đốm màu 60-70MB đặc biệt này. MS Access thông thường sẽ cho phép nhiều kết nối chỉ đọc, vì vậy điều này sẽ làm việc miễn là NHibernate không thiết lập cơ sở dữ liệu để chặn các kết nối khác.

Các vấn đề liên quan