2012-02-03 2 views
1

Возможно ли извлечь код внутри моего кода и запустить его в нескольких потоках?Многопоточность, DataReaders & Bulk Inserts ... Может ли это приложение быть многопоточным?

В приложение копирует данные из FoxPro DB на наш SQL сервер по сети (файлы являются довольно огромным, поэтому основная копия должна происходить с шагом ...

Это работает, но я хотел бы поднять вверх по скорости бит.

1) либо имеющей секцию я отмеченную работать в нескольких потоках, или в качестве альтернативы,

2), не цикл через каждый столбец в DataRow,

Я пошел на второй вариант ... (Обновленный код ниже)

КОД

private void BulkCopy(OleDbDataReader reader, string tableName, Table table) 
    { 
     if (Convert.ToBoolean(ConfigurationManager.AppSettings["CopyData"])) 
     { 
      Console.WriteLine(tableName + " BulkCopy Started."); 
      try 
      { 
       DataTable tbl = new DataTable(); 
       foreach (Column col in table.Columns) 
       { 
        tbl.Columns.Add(col.Name, ConvertDataTypeToType(col.DataType)); 
       } 

       int batch = 1; 
       int counter = 0; 

       DataRow tblRow = tbl.NewRow(); 

       while (reader.Read()) 
       { 
        counter++;     
////This section changed 
         object[] obj = tblRow.ItemArray; 
         reader.GetValues(obj); 
         tblRow.ItemArray = obj; 
////********** 
        tbl.LoadDataRow(tblRow.ItemArray, true); 

        if (counter == BulkInsertIncrement) 
        { 
         Console.WriteLine(tableName + " :: Batch >> " + batch); 
         counter = PerformInsert(tableName, tbl, batch); 
         batch++; 
        } 
       } 

       if (counter > 0) 
       { 
        Console.WriteLine(tableName + " :: Batch >> " + batch); 
        PerformInsert(tableName, tbl, counter); 
       } 

       tbl = null; 
       Console.WriteLine("BulkCopy Success!"); 
      } 
      catch (Exception) 
      { 
       Console.WriteLine("BulkCopy Fail!"); 
      } 
      finally 
      { 
       reader.Close(); 
       reader.Dispose(); 
      } 
      Console.WriteLine(tableName + " BulkCopy Ended."); 
     } 
    } 

UPDATE Я пошел за второй вариант

Я не знал, что в то время как внутри время (reader.Read()) цикл, который я мог бы сделать следующие. I't помогли значительно увеличить производительность приложений

while (reader.Read()) 
{ 
    object[] obj = tblRow.ItemArray; 
    reader.GetValues(obj); 
    tblRow.ItemArray = obj; 
    tbl.LoadDataRow(tblRow.ItemArray, true); 
} 

ответ

1

Это не может быть ответа вы после этого, но вы пробовали запустить консольное приложение в режиме выпуска первым, только с одной попыткой заявления, и с помощью индексов на читателя? Вероятно, это не будет сильно увеличивать скорость, делая его многопоточным, поскольку SQL Server станет основным узким местом.

Конечно, если вы не слишком заботитесь о целостности данных (например, ваши идентификаторы не являются последовательными), вы можете изменить тип table locking для вставок и развернуть 3-4 потока для чтения из определенных точек таблицы ,

+0

Я Защита попробовать все ваши предложения, как точки интереса, будете вы можете предоставить образец кода о том, как изменить тип блокировки таблицы, начиная с C#. Я буквально первый, о котором я слышал об этом сейчас, так что кажется, что возраст бит пространства: p (я посоветуюсь с google как хорошо) –

0

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

Но что вы можете сделать, это запланировать вставки в новом потоке, который ваш цикл не будет блокировать в течение времени, которое SQL Server должен будет вставить ваши данные.

Для этого можно использовать Task.Factory.StartNew()method. Но это сделает обработку ошибок более сложной, в том смысле, что при неудачной вставке вы могли бы обработать больше данных или в худшем случае уже есть другой поток, ожидающий новых вставок для базы данных.

4

Thre не нужно многопоточным, если вы берете ошибки начинающего, которые вы делаете. ТОНЫ медленного кода везде.

tblRow [col.Name] = reader [col.Name];

МЕДЛЕННЫЙ. НИКОГДА не используйте имя - получите индекс за пределами цикла, а затем используйте индексы. Эта строка имеет 2 (!) Словарный поиск для строки eery, занимая больше времени, чем обработка строк.

DataTables/DataSet медленно запускается с самого начала (плохой трехомальный выбор), но такой код действительно медленный.Используйте профилировщик, чтобы увидеть другие плохие элементы.

+0

Я знаю о небрежности, хотя я не знал, что индексы дадут преимущество в производительности, поэтому спасибо, я попробую сейчас ... А что касается данных, SqlBulkCopy разрешает для datatables, datarows & datareaders (которые я не мог использовать, так как некоторые из шнуры приводят к сбою всей транзакции), это был бы мой первый вариант ... –

+1

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

+0

Хорошо, обновил мой код, чтобы использовать индексы, производительность почти такая же, я забыл упомянуть, что im делает массовую вставку из 20 000 записей в каждом проходе, +/- 5mil записей за стол и 60 нечетных таблиц ... так что я знаю, что производительность по сети не будет удивительной ... вот почему, на мой взгляд, путь был состоять в том, чтобы добавление записей в datatable происходило в нескольких потоках ... опять-таки, набор данных не был моим первым выбором/маршрутом, который я взял ... объемная вставка показалась для вас способом, поэтому я взял ее сделайте свою работу ... –

0

Если вы используете .NET 4, вы можете попробовать использовать TPL и преобразовать петлю Еогеаспа в нечто вроде

Parallel.ForEach(table.Columns, col => {/*rest of function here */} 
+0

К сожалению, основная проблема полностью игнорируется - вы не можете парализовать это до бесконечности. – TomTom

Смежные вопросы