2010-08-02 1 views
1

Я использую SQLBULKCOPY для копирования некоторых таблиц данных в таблицу базы данных, однако, поскольку размер файлов, которые я копирую, иногда превышает 600 мб, у меня заканчивается нехватка памяти.sqlbulkcopy mem. управление

Я надеюсь получить некоторые советы по управлению размером таблицы, прежде чем я передам ее базе данных, чтобы я мог освободить память, чтобы продолжить запись.

Вот некоторые примеры моего кода (некоторые столбцы и строки исключаемые для простоты)

  SqlBulkCopy sqlbulkCopy = new SqlBulkCopy(ServerConfiguration); //Define the Server Configuration 
     System.IO.StreamReader rdr = new System.IO.StreamReader(fileName); 

     Console.WriteLine("Counting number of lines..."); 
     Console.WriteLine("{0}, Contains: {1} Lines", fileName, countLines(fileName)); 

     DataTable dt = new DataTable(); 

     sqlbulkCopy.DestinationTableName = "[dbo].[buy.com]"; //You need to define the target table name where the data will be copied 
     dt.Columns.Add("PROGRAMNAME"); 
     dt.Columns.Add("PROGRAMURL"); 
     dt.Columns.Add("CATALOGNAME"); 

     string inputLine = ""; 
     DataRow row; //Declare a row, which will be added to the above data table 

     while ((inputLine = rdr.ReadLine()) != null) //Read while the line is not null 
      { 
       i = 0; 
       string[] arr; 

       Console.Write("\rWriting Line: {0}", k); 
       arr = inputLine.Split('\t'); //splitting the line which was read by the stream reader object (tab delimited) 
       row = dt.NewRow(); 
       row["PROGRAMNAME"] = arr[i++]; 
       row["PROGRAMURL"] = arr[i++]; 
       row["CATALOGNAME"] = arr[i++]; 
       row["LASTUPDATED"] = arr[i++]; 
       row["NAME"] = arr[i++]; 
       dt.Rows.Add(row); 
       k++; 
     } 

     // Set the timeout, 600 secons (10 minutes) given table size--damn that's a lota hooch 
     sqlbulkCopy.BulkCopyTimeout = 600; 
     try 
     { 
      sqlbulkCopy.WriteToServer(dt); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e); 
     } 
     sqlbulkCopy.Close();//Release the resources 
     dt.Dispose(); 

     Console.WriteLine("\nDB Table Written: \"{0}\" \n\n", sqlbulkCopy.DestinationTableName.ToString()); 

    } 

Я продолжал иметь проблемы получения SqlBulkCopy на работу, и я понял, что мне нужно делать больше работы на каждая запись до того, как она была введена в базу данных, поэтому я разработал простой метод LinQ to Sql для записи записей с помощью записи, поэтому я мог редактировать другую информацию и создавать больше информации о записи по мере ее запуска,

Проблема: это метод работает довольно slo w (даже на процессоре Core i3), какие-либо идеи о том, как ускорить его (потоки?) - на одном процессорном ядре, с 1 ГБ памяти он сбой или занимает иногда 6-8 часов для записи того же объема данных, что и один SQLBulkCopy, который занимает несколько секунд. Однако он лучше управляет памятью.

  while ((inputLine = rdr.ReadLine()) != null) //Read while the line is not null 
     { 
      Console.Write("\rWriting Line: {0}", k); 
      string[] arr;    
      arr = inputLine.Split('\t'); 

      /* items */ 
      if (fileName.Contains(",,")) 
      { 
       Item = Table(arr); 
       table.tables.InsertOnSubmit(Item); 

       /* Check to see if the item is in the db */ 
       bool exists = table.tables.Where(u => u.ProductID == Item.ProductID).Any(); 

       /* Commit */ 
       if (!exists) 
       { 
        try 
        { 
         table.SubmitChanges(); 
        } 
        catch (Exception e) 
        { 
         Console.WriteLine(e); 
         // Make some adjustments. 
         // ... 
         // Try again. 
         table.SubmitChanges(); 
        } 
       } 
      } 

С вспомогательным методом:

public static class extensionMethods 
{ 
    /// <summary> 
    /// Method that provides the T-SQL EXISTS call for any IQueryable (thus extending Linq). 
    /// </summary> 
    /// <remarks>Returns whether or not the predicate conditions exists at least one time.</remarks> 
    public static bool Exists<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate) 
    { 
     return source.Where(predicate).Any(); 
    } 
} 
+1

возможно также утилизации РДР может быть хорошей идеей, –

+0

спасибо - я буду держать это в виду Я интересно, если я распоряжаюсь мой читатель, прежде чем Я заканчиваю читателя, прежде чем закончить чтение каждого файла. Я потеряю свой темп, пока я читаю прямо, и у меня ошибка в памяти, пока я читаю не во время написания ... Любые мысли о том, как я вернусь туда, где я был в файле? –

+0

см. Выше комментарий ... –

ответ

2

Попробуйте указать свойство BATCHSIZE 1000, который будет партия до вставки в 1000 звукозаписывающей партии в, а не всей партии. Вы можете настроить это значение, чтобы найти оптимальное. Я использовал sqlbulkcopy для данных аналогичного размера, и он работает хорошо.

+0

Спасибо, я добавил это и начал писать каждые 100 тыс. Записей, я думаю, что моя проблема связана с объектом для чтения файлов, потому что каждый раз я теряю память примерно в одном месте - пытаясь выяснить как я мог сохранить свое место в файле, так как сейчас я читаю прямо сейчас ... –

+0

Я все еще не думаю, что проблема с фильтрами. Вы попробовали размер партии около 1000? По-видимому, наиболее эффективным является дозирование около 1000-2000 записей. Если вы уверены, что это файл, то вы можете открыть файл, прочитать тысячу записей, сохранить позицию, сделать объемную вставку, а затем закрыть файл. Откройте его снова и установите позицию в последнюю позицию и прочитайте другую партию. –

+0

Вы должны быть правы, потому что у меня есть фактическая копия в блоке «try», и я получаю исключение из памяти, поэтому оно должно быть связано с чем-то в блоке try, иначе я бы не справился с этим должным образом. Попытайтесь сохранить позицию моего файла и сообщить о результатах. –

1

Столкнувшись с той же проблемой, выяснилось, что проблема OutOfMemory Exception была в DataTable.Rows ограничение максимального количества. Решенный с воссоздающим столом с максимальным ограничением 500000 строк. Надежда, мое решение будет полезно:

var myTable = new System.Data.DataTable(); 
myTable.Columns.Add("Guid", typeof(Guid)); 
myTable.Columns.Add("Name", typeof(string)); 

int counter = 0; 

foreach (var row in rows) 
{ 
    ++counter; 

    if (counter < 500000) 
    { 
     myTable.Rows.Add(
      new object[] 
      { 
       row.Value.Guid, 
       row.Value.Name 
      }); 
    } 
    else 
    { 
     using (var dbConnection = new SqlConnection("Source=localhost;...")) 
     { 
      dbConnection.Open(); 
      using (var s = new SqlBulkCopy(dbConnection)) 
      { 
       s.DestinationTableName = "MyTable"; 

       foreach (var column in myTable.Columns) 
        s.ColumnMappings.Add(column.ToString(), column.ToString()); 

       try 
       { 
        s.WriteToServer(myTable); 
       } 
       catch (Exception ex) 
       { 
        Console.WriteLine(ex.Message); 
       } 
       finally 
       { 
        s.Close(); 
       } 
      } 
     } 

     myTable = new System.Data.DataTable(); 
     myTable.Columns.Add("Guid", typeof(Guid)); 
     myTable.Columns.Add("Name", typeof(string)); 

     myTable.Rows.Add(
      new object[] 
      { 
       row.Value.Guid, 
       row.Value.Name 
      }); 

     counter = 0; 

    } 
}