也记一次性能优化: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);
最后,采用该解决方法,订单明细数据基本瞬间就查询出来了,效果拔群啊,该优化任务圆满完成。
也记一次性能优化:LINQ to SQL中Contains方法的优化的更多相关文章
- LINQ to SQL 中 Concat、Union、Intersect、Except 方法的使用
Ø 前言 LINQ to SQL 中需要对两个或多个数据集进行操作,比如:合并.取交集等,主要使用下面四个方法,这四个方法都是 System.Linq.IQueryable<out T> ...
- linq to sql中的自动缓存(对象跟踪)
linq to sql中,对于同一个DataContext上下文环境,根据表主键选择记录时(当然这里所指的“记录”会自动转成“对象”),如果该记录已经被select过,默认情况下会被自动缓存下来,下次 ...
- LINQ TO SQL 中的join(转帖)
http://www.cnblogs.com/ASPNET2008/archive/2008/12/21/1358152.html join对于喜欢写SQL的朋友来说还是比较实用,也比较容易接受的东西 ...
- Linq to sql中使用DateDiff()
Linq to sql中使用DateDiff() 计算时间差的方法 第一种办法: from p in PurchaseLists where EntityFunctions.DiffDays(p.Cr ...
- Linq to sql中继承类映射转换问题
类型为的数据成员“Int32 VTOUID”不是类型的映射的一部分.该成员是否位于继承层次结构根节点的上方? 想躲开Linq to sql中问题限制可真是不容易: http://www.makaido ...
- Linq To Sql中实现Left Join与Inner Join使用Linq语法与lambda表达式
当前有两个表,sgroup与sgroupuser,两者通过gKey关联,而sgroup表记录的是组,而sgroupuser记录是组中的用户,因此在sgroupuser中不一定有数据.需要使用Left ...
- wcf+linq to sql中关联查询返回数据问题
前段时间准备采用wcf+nh框架开发sl程序,发现采用nh开发不适合我的中型.并且快速开发项目,所以综合考量了下,决定采用wcf+linq to sql . 但是此模式也有缺点,也是linq to s ...
- linq to sql 中增删改查
首先我先说一下,如果真的要用linq做项目的话,也会是比较方便的.已经尝试了在三层架构中应用linq to sql 比较方便. //有三个不同的数据库表,所以写法不一样 public class Li ...
- 关于Linq to Sql 中的left join 中defaultifempty的相关注意事项
在使用Linq to Sql的时候,进行两个表的左连接的时候要注意defaultifempty的使用,这个函数本来的意思即是:如果为空则使用默认值代替,默认值为 NULL ,当然也可以使用defaul ...
随机推荐
- Android核心类源码分析
Handler流程1.首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象:因为Looper.prepare()在一个线程中只能调用 ...
- SpringMVC中 Session的使用情况
在SpringMVC中,使用Session可以用通过两种方式 1.servlet-api 即HttpSession session.setAttritute(),session.getAttribut ...
- ConvexScore
题目描述 You are given N points (xi,yi) located on a two-dimensional plane. Consider a subset S of the N ...
- HEOI 2012 旅行问题
2746: [HEOI2012]旅行问题 Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 1009 Solved: 318[Submit][Statu ...
- vijos 1004 伊甸园日历游戏 博弈+打表找规律
描述 Adam和Eve玩一个游戏,他们先从1900.1.1到2001.11.4这个日期之间随意抽取一个日期出来.然后他们轮流对这个日期进行操作: 1 : 把日期的天数加1,例如1900.1.1变到19 ...
- JAVA中3种将byte转换为String的方法
HttpClient 类库中GetMethod类的getResponseBody方法返回的是byte[]类型,要操作起来不方便,我想把它转化成String类型. 查了网上的资料,有说法认为用这种方法比 ...
- [J]computer network tarjan边双联通分量+树的直径
https://odzkskevi.qnssl.com/b660f16d70db1969261cd8b11235ec99?v=1537580031 [2012-2013 ACM Central Reg ...
- Python3 PyPAML 模块(配置文件的操作)
YAML 是专门用来写配置文件的语言,非常简洁和强大 它的基本语法规则如下: 1.大小写敏感 2.使用缩进表示层级关系 3.缩进时不允许使用Tab键,只允许使用空格. 4.缩进的空格数目不重要,只要相 ...
- Ubuntu 14.04 ThinkPad E431无线网卡驱动安装
Ubuntu 14.04下安装无线网卡驱动. sudo apt-get install linux-headers-generic build-essential dkms sudo apt-get ...
- [Linux]Linux printf 输出重定向【转】
转自:http://www.cnblogs.com/aaronLinux/p/6765145.html?utm_source=itdadao&utm_medium=referral 方法一 # ...