Перебирая много строк - PullRequest
       5

Перебирая много строк

3 голосов
/ 11 марта 2012

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

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

Ответы [ 2 ]

2 голосов
/ 11 марта 2012

Сначала: Не используйте 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) зависит от фактической выполняемой обработки и, возможно, должен быть скорректирован.
  • Синхронизация имеет свои собственные проблемы, вы должны быть очень осторожны с общими ресурсами
0 голосов
/ 11 марта 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...