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******************************//

  • 相关阅读:
    linux软件安装方式
    docker 安装 jenkins touch: cannot touch ‘/var/jenkins_home/copy_reference_file.log’: Permission denied Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?
    [ERR] Node goodsleep.vip:6379 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
    Linux 常用命令 服务器间scp 用户 export 创建文件、软连接
    redis 安装 集群 主从 哨兵 docker
    WPF密码框中禁止复制、粘贴
    Application 统计在线人数
    【转义字符】HTML 字符实体&lt; &gt: &amp;等
    SQL语句统计每天的数据
    正则表达式计算代码数
  • 原文地址:https://www.cnblogs.com/tylertang/p/4929308.html
Copyright © 2011-2022 走看看