实体模型.net从MySQL性能问题查询100万条记录

Gur*_*ruC 4 c# mysql ado.net entity-framework

我正在使用一个ADO .Net Entity Model查询MySQL数据库.我对它的实现和使用感到非常高兴.我决定看看如果我查询了100万条记录会发生什么,并且它有严重的性能问题,我不明白为什么.

系统挂起一段时间,然后我得到

  • 死锁异常
  • MySQL例外

我的代码如下::

      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);
       }
Run Code Online (Sandbox Code Playgroud)

我的问题是为什么ToList()花了这么长时间?

另外,如何避免此异常以及查询百万条记录的理想方式是什么?

msa*_*het 12

查询一百万条记录的理想方法是使用a IQueryable<T>来确保在您需要实际数据之前实际上没有在数据库上执行查询.我非常怀疑你一次需要一百万条记录.

它是死锁的原因是你要求MySQL服务器从数据库中提取那些百万条记录,然后按顺序排序EMPLOYEE_ID,然后让你的程序将它返回给你.所以我想象死锁是来自你的程序等待它完成,以及你的程序将其读入内存.MySQL问题可能与超时问题有关.

var data部分快速工作的原因是因为你实际上还没有做任何事情,你刚刚构建了查询.当你调用时,ToList()所有SQL和SQL的读取都被执行.这就是所谓的Lazy Loading.

我建议尝试如下:

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

然后,当你真正需要列表中的东西时,只需要调用

data.Where(/* your filter expression */).ToList()
Run Code Online (Sandbox Code Playgroud)

因此,如果您需要ID为10的员工.

var employee = data.Where(e => e.ID == 10).ToList();
Run Code Online (Sandbox Code Playgroud)

或者,如果您需要姓氏以S开头的所有员工(我不知道您的表是否有姓氏列,只是一个例子).

var employees = data.Where(e => e.LastName.StartsWith("s")).ToList();
Run Code Online (Sandbox Code Playgroud)

或者,如果您想以100块的方式浏览所有员工

var employees = data.Skip(page * 100).Take(100).ToList();
Run Code Online (Sandbox Code Playgroud)

如果您想进一步推迟数据库调用,则无法调用ToList()并在需要时使用迭代器.因此,假设您想要将名称以A开头的人的所有工资加起来

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

 foreach(var employee in salaries)
 {
     salaryTotal += employee.Salary;
 }
Run Code Online (Sandbox Code Playgroud)

这只会做一个类似的查询

Select Salary From EmployeeTable Where ID = @ID
Run Code Online (Sandbox Code Playgroud)

导致一个非常快速的查询,只在您需要时获取信息,并且只获取您需要的信息.

如果出于某些疯狂的原因,您想要实际查询数据库的所有百万条记录.忽略这会占用大量系统资源这一事实我建议以块的形式进行,你可能需要使用块大小来获得最佳性能.

一般的想法是进行较小的查询以避免数据库出现超时问题.

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));
}
Run Code Online (Sandbox Code Playgroud)

我选择使用a,HashSet<T>因为它们是为大型数据集而设计的,但我不知道哪些性能看起来像1,000,000个对象.

  • +1.拉动am illion条目接近滥用数据库,计算机和实体框架.规则1:AWLAYS只能拉你需要的东西. (3认同)
  • 我想补充说,有时你甚至不需要使用`ToList`,因为你只想迭代结果.迭代器也会触发查询,但项目列表将不会存储在内存中. (2认同)
  • @LadislavMmka,是的,我要把它扩展到这个答案 (2认同)