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);

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

  • 相关阅读:
    telent connection refused
    (待整理)flume操作----------hivelogsToHDFS案例----------运行时,发生NoClassDefFoundError错误
    Java核心技术36讲----------Exception和Error有什么区别
    Hive操作之向分区表中导入数据的语义错误
    java的值传递机制
    notepad无法对linux中的文件进行修改???
    读书笔记----------第五章----------字符串
    读书笔记----------第四章----------流程控制
    java中子类会继承父类的构造方法吗?
    文章分类
  • 原文地址:https://www.cnblogs.com/daretodream2014/p/4523994.html
Copyright © 2011-2022 走看看