Модель сущности .net, запрашивающая 1 миллион записей из проблем производительности MySQL - PullRequest
4 голосов
/ 13 марта 2011

Я использую ADO .Net Entity Model для запроса базы данных MySQL. Я был очень рад его реализации и использованию. Я решил посмотреть, что произойдет, если я запрошу 1 миллион записей, и у него будут серьезные проблемы с производительностью, и я не понимаю, почему.

Система некоторое время зависает, а затем я получаю либо

  • Исключение из тупика
  • MySQL Exception

Мой код выглядит следующим образом:

      try
        {
            // works very fast
            var data = from employees in dataContext.employee_table
                            .Include("employee_type")
                            .Include("employee_status")
                       orderby employees.EMPLOYEE_ID descending                            
                       select employees; 

            // This hangs the system and causes some deadlock exception
            IList<employee_table> result = data.ToList<employee_table>(); 

            return result;
       }
       catch (Exception ex)
       {
            throw new MyException("Error in fetching all employees", ex);
       }

Мой вопрос: почему ToList () занимает так много времени?

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

1 Ответ

12 голосов
/ 13 марта 2011

Идеальный способ запросить миллион записей - это использовать IQueryable<T>, чтобы убедиться, что вы фактически не выполняете запрос к базе данных, пока вам не понадобятся фактические данные.Я очень сомневаюсь, что вам нужен миллион записей одновременно.

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

Причина, по которой раздел var data работает быстро, заключается в том, что вы на самом деле еще ничего не сделали, вы только что создали запрос.когда вы вызываете ToList(), тогда выполняется весь SQL и чтение SQL.Это то, что известно как «Ленивая загрузка».

Я бы предложил попробовать это следующим образом:

        var data = from employees in dataContext.employee_table
                        .Include("employee_type")
                        .Include("employee_status")
                   orderby employees.EMPLOYEE_ID descending                            
                   select employees;

Тогда, когда вам действительно понадобится что-то из списка, просто наберите

data.Where(/* your filter expression */).ToList()

Так что, если вам нужен сотрудник с ID 10.

var employee = data.Where(e => e.ID == 10).ToList();

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

var employees = data.Where(e => e.LastName.StartsWith("s")).ToList();

Или, если вы хотите просмотреть всех сотрудников порциями по 100

var employees = data.Skip(page * 100).Take(100).ToList();

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

 var salaries = data.Where(s => s.LastName.StartsWith("A"))

 foreach(var employee in salaries)
 {
     salaryTotal += employee.Salary;
 }

. Это только сделало бы запрос, который выглядел бы как

Select Salary From EmployeeTable Where ID = @ID
* 1032.* В результате получается очень быстрый запрос, который получает информацию только тогда, когда вам это нужно, и только ту информацию, которая вам нужна.

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

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

int ChunkSize = 100; //for example purposes
HashSet<Employee> Employees - new HashSet<Employee>;

//Assuming it's exactly 1 Million records

int RecordsToGet = 1000000;

for(record = 0; record <= RecordsToGet; record += ChunkSize)
{
    dataContext.EmployeeTable.Skip(record).Take(ChunkSize).ForEach(e => HashSet.Add(e));
}

Я решил использовать HashSet<T>, поскольку они предназначены для больших наборов данных, но я не знаю, как будет выглядеть производительность1 000 000 объектов.

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