zoukankan      html  css  js  c++  java
  • EF性能调优

    首先说明下:

    第一次运行真是太慢了,处理9600多个员工数据,用了81分钟!!

    代码也挺简单,主要是得到数据--》对比分析--》插入分析结果到数据库。用的是EF的操作模式。

      public void AllocateAllPlans()
            {
                var employees = _efWorker.EmployeeRepository.FindAll(filter: p => p.Status.Trim().ToUpper() == "ACTIVE");
                var plans = _efWorker.BenefitPlanRepository.FindAll(includeProperties: "PlanEligibility", orderBy: query => query.OrderBy(p => p.Priority), filter: p => p.Status.Trim().ToUpper() == "ACTIVE");
                if (employees == null || plans == null)
                    return;
                AllocatePlanForEmployee(employees, plans);
                _efWorker.SaveChanges();
            }
            /// <summary>
            /// 根据输入员工和计划,生成PlanEntitlement以及Account初始数据
            /// </summary>
            /// <param name="employees"></param>
            /// <param name="plans"></param>
            public void AllocatePlanForEmployee(IEnumerable<Employee> employees, IEnumerable<BenefitPlan> plans)
            {
                //初始化员工积分账户,默认积分为0
                AccountingHelper accountingHelper = new AccountingHelper(_efWorker);
                foreach (var employee in employees)
                {
                    //先验证业务逻辑相关基本信息
                    List<string> errorMsg;
                    if (!_insuredInfoValidator.ValidateEmployeeInfo(employee, out  errorMsg))
                        throw new Exception(string.Join(@"
    ", errorMsg.ToArray()));
                    bool joinedPlan = false;
                    foreach (var plan in plans)
                    {
                        var eligibilitys = plan.PlanEligibility;
                        if (_eligibilityEvaluator.MatchPlan(employee, eligibilitys))
                        {
                            //添加该员工与计划的对应数据到表PlanEntitlement
                            var planEntitlement = new PlanEntitlement
                            {
                                Id = Guid.NewGuid(),
                                PlanId = plan.Id,
                                EmployeeId = employee.Id,
                                JoinPlanDate = DateTime.Now,
                                //SelectionOpenDate = plan.SelectionOpenDate,
                                //SelectionCloseDate = plan.SelectionCloseDate,
                                Status = "ACTIVE"
                            };
                            _efWorker.PlanEntitlementRepository.Insert(planEntitlement);
                            accountingHelper.InitAccount(planEntitlement.Id, employee.Id, 0m, "EE");
                            joinedPlan = true;
                            break;//根据优先级,员工分配到一个计划就跳出计划匹配循环
                        }
                    }
                    if (joinedPlan == false)
                    {
                        throw new Exception("Employee not match any plan,EmployeeId=" + employee.Id.ToString());
                    }
                }
            }

    代码写得丑,大家将就看,有什么改进建议请提出。多谢指教!

    第一次优化是把查询出来的原始数据跟踪去掉:

      public IEnumerable<TEntity> FindAll(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
                string includeProperties = "")
            {
                IQueryable<TEntity> query = dbSet;
                if(filter!=null)
                {
                    query = query.Where(filter);
                }
                foreach(var includeProperty in includeProperties.Split(new char[]{','},StringSplitOptions.RemoveEmptyEntries))
                {
                    query = query.Include(includeProperty);
                }
                if(orderBy!=null)
                {
                    return orderBy(query).AsQueryable().AsNoTracking().ToList();//这里之前没有添加AsNoTracking()方法
                }
                else
                {
                    return query.AsQueryable().AsNoTracking().ToList();//这里之前没有添加AsNoTracking()方法
                }
            }

    看注释,就改动了下获取数据集的方法,同样多的数据,执行完毕只花了12分钟。

    81分钟的图就不贴出来了,跑81分钟个太坑了。

    12分钟还是太慢,看了各位大大的博客,于是准备再把插入数据那段优化下。

    http://www.cnblogs.com/linfei721/archive/2013/06/07/3123579.html

      public void AllocateAllPlans()
            {
                var employees = _efWorker.EmployeeRepository.FindAll(filter: p => p.Status.Trim().ToUpper() == "ACTIVE");
                var plans = _efWorker.BenefitPlanRepository.FindAll(includeProperties: "PlanEligibility", orderBy: query => query.OrderBy(p => p.Priority), filter: p => p.Status.Trim().ToUpper() == "ACTIVE");
                if (employees == null || plans == null)
                    return;
                _efWorker.context.Configuration.AutoDetectChangesEnabled = false;//设置不跟踪标记
                AllocatePlanForEmployee(employees, plans);
                _efWorker.SaveChanges();
            }

    依葫芦画瓢,先改了试试看。
    !!!果然拖拉机变灰机了。

    只用了8秒,有图有真相啊。等等,先去检查下数据正确不。

    看起来数据没有问题。

    总结:

    .AsNoTracking()和context.Configuration.AutoDetectChangesEnabled = false这两个设置都是让EF不对当前的数据集做变化跟踪,因此如果在数据集需要做更新或者删除操作时,这两个方法不能用,当然可以根据业务需求,灵活使用它们。
    补充阅读:
    http://www.cnblogs.com/libingql/p/3390012.html

    续:
    关闭跟踪虽然速度上去了,但是也留下了隐患,比如在跟踪状态下能正常保存/更新的数据,在不跟踪时却要小心处理。
    这里就遇到一个

    //************************EF中,关闭自动跟踪_efWorker.SetDetectChanges(false)时
    //********主从表插入的时候应该先构造好主从的完整对象(先构建主对象,然后将从对象加入),productMenu->
    //productMenu.ProductMenuItem.Add(productMenuItem)->productMenuItem.ProductMenuItemOption.Add(productMenuItemOption)
    //********最后再将主对象Insert到Repository,这样才能保证从对象所有数据插入到数据库,如果先insert了主对象,再加入从对象对应关系,EF将不会保存从对象

    //最后再saveChanges******************************//

  • 相关阅读:
    小甲鱼与客服的对话,代码与解析
    (role,line_spoken) = each_line.split(':',2) 小甲鱼python 一个任务
    python open() 方法 No such file or directory: 应该怎么解决
    并发编程
    并发编程
    并发编程
    并发编程
    并发编程
    并发编程
    并发编程
  • 原文地址:https://www.cnblogs.com/tylertang/p/4929308.html
Copyright © 2011-2022 走看看