2012-03-11 8 views
3

У меня есть проблема времени с прохождением через 1 миллион потенциальных строк из базы данных. Я в основном вытаскиваю строки в DataTable и прокручиваю их, но он замедляется. Какая альтернатива? Я могу разбить эти ряды на куски размером 20 000 штук. Можно ли использовать параллельную обработку в C#? В основном код проходит через каждую потенциальную запись, которая соответствует определенному запросу, и пытается выяснить, является ли это законной записью. Вот почему каждую запись нужно индивидуально посещать. Запись для одного объекта может достигать 10 миллионов строк. Подходы кажутся параллельной обработкой на нескольких компьютерах или PP в одиночной машине с несколькими ядрами или какой-то структурой данных/сменой подхода?Зацикливание через множество строк

Любые мнения, мысли и догадки полезны, чтобы сделать это быстро и разумно?

ответ

2

Во-первых: Не используйте DataTable для таких операций, как эти:

  • это медленно
  • это отнимает слишком много памяти
  • и вам нужно долго ждать, прежде чем вы сможете начать обработка данных
    • За это время дополнительные ядра ничего не делают, поскольку считывание данных в DataTable не является параболическим.
    • Кроме того, при чтении данных, как правило, почти используется ЦП, поскольку основной причиной является сеть или другая задержка ввода-вывода.

Итак, еще раз: Не используйте DataTable для таких операций, как это.

Вместо этого используйте DataReader. Это позволяет сразу же начать потреблять/обрабатывать данные, а не ждать, пока он будет загружен. Простейший вариант будет (пример для MS SQL Server):

var command = new SqlCommand() 
{ 
    CommandText = "SELECT * FROM Table"; 
    Connection = new SqlConnection("InsertConnectionString"); 
}; 

using(var reader = command.ExecuteReader()) 
{ 
    while(reader.Read()) 
    { 
    var values = new object[reader.FieldCount]; 
    reader.GetValues(values); 

    // process values of row 
    } 
} 

читатель будет заблокирован во время выполнения кода обработки, то есть не больше строк считываются из БД.
Если код обработки является тяжелым, может потребоваться использовать библиотеку Task для создания задач, которые выполняют проверку, что позволит вам использовать несколько ядер. Тем не менее, есть накладные создания Task, если один Task не содержит достаточного количества «работы» вы можете партия пару строк вместе:

public void ReadData() 
{ 
    var taskList = new List<Task<SomeResultType>>(); 

    var command = new SqlCommand() 
    { 
    CommandText = "SELECT * FROM Table"; 
    Connection = new SqlConnection("InsertConnectionString"); 
    }; 
    using(var reader = command.ExecuteReader()) 
    { 
    var valueList = new List<object[]>(100); 
    while(reader.Read()) 
    { 
     var values = new object[reader.FieldCount]; 
     reader.GetValues(values); 

     valueList.Add(values); 

     if(valueList.Count == 100) 
     { 
     var localValueList = valueList.ToList(); 
     valueList.Clear(); 

     taskList.Add(Task<SomeResultType>.Factory.StartNew(() => Process(localValueList)); 
     } 
    } 
    if(valueList.Count > 0) 
     taskList.Add(Task<SomeResultType>.Factory.StartNew(() => Process(valueList)); 
    } 

    // this line completes when all tasks are done 
    Task.WaitAll(taskList.ToArray()); 
} 

public SomeResultType Process(List<object[]> valueList) 
{ 
    foreach(var vals in valueList) 
    { 
    // put your processing code here, be sure to synchronize your actions properly 
    } 
} 
  • Пакетный размер (в настоящее время 100) зависит от фактической обработка и, возможно, потребуется скорректировать.
  • Synchronizing держит это собственные проблемы, вы должны быть очень осторожны, об общих ресурсах
+0

Хорошее объяснение Но у меня есть некоторые вопросы: 1, что было бы лучше, решение, которое вы предложили, или создание нескольких задач, каждый из которых использует SQLReader для чтения ряда строк из базы данных (например,основанный на пейджинге), особенно в случае обработки результатов, не очень тяжелый. 2-есть ли существенная разница в производительности между Task BackgroundWork? –

0

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