zoukankan      html  css  js  c++  java
  • 也记一次性能优化:LINQ to SQL中Contains方法的优化

      距离上一篇博文更新已经两个月过去了。在此,先表一表这两个月干了些啥:

      世界那么大,我也想去看看。四月份的时候,我入职了上海的一家电商公司,职位是.NET高级开发工程师。工作一个月,最大的感受是比以前小城市匆忙了许多,工作压力大了许多,开发方式更加的正规,不过各种流程也更加的繁杂细琐。在写代码的时候,一定要严谨细心,该验证参数合法性的时候验参,该抛异常的时候抛异常,该写日志的时候写日志,因为一个不小心而报黄页或者主流程无法顺利进行下去,是很没面子的事情。另外,我也更加关注代码的性能问题,开发环境和生产环境的数据量根本不是一个数量级的,也许在开发环境页面加载速度很快一旦上了产线却慢得无法忍受。

      好了,废话少说,言归正传。昨天,Leader安排了一个性能优化的任务。商家要导出订单信息,如果查询的订单时间间隔比较小,没什么问题,查询的订单时间跨度大了,就非常非常非常慢了。项目使用的ORM是LINQ to SQL,至于为什么要使用,这属于历史遗留问题了。

      有一个订单明细表,里面有数十个字段,为了简化问题,我们建一个简单的实体:

    public class OrderItem
    {
        public string Id{ get; set; }
        public string OrderId{ get; set; }//订单编号
        public string ProductId{ get; set; }//商品ID
        public int ProductQuantity{ get; set; }//商品数量
    }

      一个方法一个方法排查,最后找到了问题的所在:

    List<OrderItem> orderItems=OrderRepository.Find(orderItem=>orderIdList.Contains(orderItem.OrderId)).ToList();

      orderIdList是一个List<string>集合,存储了查询时间段内的订单编号。当订单编号的数量大于50时查询就开始变慢,大于100时就非常慢了。我在orderIdList里填充了1000个有效的订单编号,然后用SqlServer Profiler监控,发现上面一句LINQ查询表达式动态编译成SQL语句竟然花费了几十秒的时间,生成的SQL大概如下:

        SELECT Id,OrderId,ProductId,ProductQuantity   
        FROM OrderItems
        WHERE OrderId IN (......)

      上面的SQL执行时间大约是0.7秒,已经为订单编号OrderId字段建立了索引,测试数据库里的数据大约是55万条。

        为了解决上面LINQ查询表达式动态编译成SQL耗时比较长的问题,最后决定直接执行SQL语句,并且IN查询改为JOIN查询,简单粗暴。解决方法如下:

    //创建临时表SQL,存储查询时间段内的订单编号
    string createSql = "CREATE TABLE #TmpOrderId(OrderId varchar(36));";
    
    //订单编号插入SQL
    string orderIds = orderIdList.Aggregate(string.Empty,(current,id) => current + ("('" + id + "'),"));
    orderIds = orderIds.Remove(orderIds.LastIndexOf(','));
    string insertSql = "INSERT INTO #TmpOrderId VALUES " + orderIds + ";";
    
    //JOIN查询SQL
    string joinSql = "SELECT T1.Id,T1.OrderId,T1.ProductId,T1.ProductQuantity FROM OrderItems AS T1 JOIN #TmpOrderId AS T2 ON T1.OrderId=T2.OrderId;";
    
    //三条SQL语句要放在一个会话里执行,否则会报找不到临时表#TmpOrderId异常
    IEnumerable<OrderItem> query = DataContext.ExecuteQuery<OrderItem>(createSql + insertSql + joinSql);

      最后,采用该解决方法,订单明细数据基本瞬间就查询出来了,效果拔群啊,该优化任务圆满完成。

  • 相关阅读:
    228. Summary Ranges
    227. Basic Calculator II
    224. Basic Calculator
    222. Count Complete Tree Nodes
    223. Rectangle Area
    221. Maximal Square
    220. Contains Duplicate III
    219. Contains Duplicate II
    217. Contains Duplicate
    Java编程思想 4th 第4章 控制执行流程
  • 原文地址:https://www.cnblogs.com/daretodream2014/p/4523994.html
Copyright © 2011-2022 走看看