如何优化我的实体框架查询以获得更好的性能和更高的可读性

Posted

技术标签:

【中文标题】如何优化我的实体框架查询以获得更好的性能和更高的可读性【英文标题】:How can i optimize my entity framework query for better performance and more readability 【发布时间】:2016-07-16 11:29:38 【问题描述】:

我的网站中有一个名为HotelDetail 的重页,该页面将加载与酒店相关的几项内容。酒店、酒店的服务、到酒店的目的地、用户的cmets、酒店的房间及其服务、价格和容量。 所有这些都将使用下面的代码一次性加载,现在我想优化这段代码,有什么解决方案可以优化它以获得更好的性能和更高的可读性?有没有办法一次不加载所有内容?

  public PlaceViewModel GetPlaceDetail(string languageKey,string catKey , string placeKey, SearchViewModel searchOptions)
        
                DateTime startDate = searchOptions.CheckIn.ToMiladiDateTime();
                DateTime endDate = searchOptions.CheckOut.ToMiladiDateTime();
                int nights = (int)endDate.Subtract(startDate).TotalDays;
                placeViewModel.NightCount = nights;
                var query = (from r in _unitOfWork.RoomServiceRepository.Get()
                             join
                                a in _unitOfWork.InventoryRepository.Get()
                                on r equals a.RoomService
                             where r.Room.Place.Id == place.Id && !r.SoftDelete && !r.Room.SoftDelete &&
                                   a.Date >= startDate && a.Date < endDate && (a.CertainAvailability + a.FloatAvailability) > 0
                             select new  a, MaxCapacity = r.Room.Capacity + r.ExtraCapacity, r.RoomId );

                placeViewModel.HasAvailability = query.ToList().Count != 0;

               var grp = query.GroupBy(y => y.a.RoomServiceId)
                    .Select(z => new 
                        key = z.Key,
                        count = z.Count(),
                        minAvail = z.Min(ax => ax.a.CertainAvailability + ax.a.FloatAvailability),
                        minDate = z.Min(y => y.a.Date),
                        minPrice = z.Min(ax=>ax.a.Price),
                        price = z.Average(ax=>ax.a.Price) );

                var tmp = query.Where(x => grp.Any(q => 
                    q.key == x.a.RoomServiceId && 
                    q.count == nights &&
                    q.minDate == x.a.Date)).ToList();
                foreach (var item in tmp)
                
                    var roomViewModel = placeViewModel.Rooms.FirstOrDefault(x => x.Id == item.RoomId);
                    var avail = new AvailabilityViewModel(item.a, item.MaxCapacity);
                    avail.Availability = grp.FirstOrDefault(x => x.key == item.a.RoomServiceId).minAvail;
                    var otherInfos = grp.SingleOrDefault(x => x.key == item.a.RoomServiceId);
                    avail.JabamaPrice = otherInfos.price;
                    avail.JabamaMinPriceInPeriod = otherInfos.minPrice;
                    roomViewModel.Availabilites.Add(avail);
                    if (maxDiscount == null || (maxDiscount != null &&(maxDiscount.BoardPrice - maxDiscount.JabamaPrice) < (avail.BoardPrice - avail.JabamaPrice)))
                        maxDiscount = avail;
                    if (minPrice == null || (minPrice != null && avail.JabamaPrice > 0 && minPrice.JabamaPrice > avail.JabamaPrice))
                        minPrice = avail;
                
                var discountQuery = tmp.Where(x => x.a.RoomService.ExtraCapacity == 0 && x.a.Date == minPrice.Date);
                try
                
                    if (discountQuery.Any())
                        maxDiscountOfMinPercentageDay = tmp != null && minPrice != null ? discountQuery.Max(x => (x.a.BoardPrice - x.a.Price) / x.a.BoardPrice * 100) : 0;
                    else
                        maxDiscountOfMinPercentageDay = 0;

                
                catch (Exception)
                
                    maxDiscountOfMinPercentageDay = 0;
                
                foreach (var roomVM in placeViewModel.Rooms)
                
                    if (roomVM.Availabilites.Count() == 0)
                        roomVM.Availabilites.Add(new AvailabilityViewModel(-1));
                

【问题讨论】:

这肯定取决于您如何使用 UI 中的数据。您应该只一眼就能看到显示的内容。 其实都得一目了然,不过这段代码我也需要优化一下,变复杂了, 您需要更明确地说明您正在寻找哪种类型的优化:性能、可读性、可扩展性等... 我的目标是提高性能和可读性 一个快速的胜利是将query.ToList() 的结果存储在一个变量中,然后继续使用该内存列表。 【参考方案1】:

我对 Linq 并不熟悉,但我确实知道 SQL 的一些陷阱。我注意到的一件事是您(和许多其他人!)使用.Count != 0 来确定是否存在匹配记录。在 SQL 中,这是一种非常低效的方法,因为系统将有效地遍历整个表以查找和计算与先决条件匹配的记录。在这种情况下,我建议使用WHERE EXISTS() 构造;我相信 Linq 有类似 .Any() 的东西。

这也是你在现实生活中所做的:当有人问你冰箱里是否还有奶酪时,你不会开始数你能找到的所有类型的奶酪,而是在第一种奶酪后停下来您看到并回答“是的,有”;翻遍整个冰箱没有任何附加价值,只会花费额外的时间。

PS:roomVM.Availabilites.Count() == 0 可能也是如此,使用 逆逻辑...

可能会更好地处理

免责声明:可能是 EntityFwk 足够聪明,可以在后台为您优化它……我不知道;我非常怀疑,但就像我说的,我不是专家。我建议首先弄清楚当前代码的每个部分需要多长时间,然后首先优化最慢的部分。 基线还可以让您更好地了解您的更改是否会产生任何影响,无论是积极的还是消极的。

【讨论】:

以上是关于如何优化我的实体框架查询以获得更好的性能和更高的可读性的主要内容,如果未能解决你的问题,请参考以下文章

并发增加cpu涨幅不大怎么办

URLConnection 或 HTTPClient:哪个提供更好的功能和更高的效率?

HttpClient vs HttpWebRequest 以获得更好的性能、安全性和更少的连接

Greenplum 简单性能测试与分析

如何用 kevent() 替换 select() 以获得更高的性能?

raid配置在当前设置中不受支持