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

时间:2011-03-13 15:27:08

标签: c# mysql entity-framework ado.net

我使用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);
       }

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

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

1 个答案:

答案 0 :(得分:12)

查询一百万条记录的理想方法是使用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

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

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

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

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个对象。