也记一次性能优化: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);

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

时间: 2024-08-02 12:55:34

也记一次性能优化:LINQ to SQL中Contains方法的优化的相关文章

LINQ to SQL 中 Concat、Union、Intersect、Except 方法的使用

?  前言 LINQ to SQL 中需要对两个或多个数据集进行操作,比如:合并.取交集等,主要使用下面四个方法,这四个方法都是 System.Linq.IQueryable<out T> 接口的扩展方法,并且都是延迟加载方法,下面是使用的简单示例. ?  示例数据,数据表:Subject(科目表).Score(成绩表) 1.   Concat() 方法 1)   方法声明 public static IQueryable<TSource> Concat<TSource>

LINQ TO SQL 中的join(转帖)

http://www.cnblogs.com/ASPNET2008/archive/2008/12/21/1358152.html join对于喜欢写SQL的朋友来说还是比较实用,也比较容易接受的东西.在LINQ TO SQL中,写多表查询,同样可以写join,只是它有它自己的语法要求而已,语义都是一样的,下面我来讲下LINQ TO SQL中的join最基本的形式:都是最简单的,当然还有其它方面的内容,如:怎样加上过滤条件,如何分组,如何排序等等,为了单纯说join的用法,这里就简化下. Cod

Linq To Sql 中未将对象引用设置到对象的实例

我们在DAL对方法进行封装 public void Delete(T entity) { db.GetTable<T>().DeleteOnSubmit(entity); db.SubmitChanges(); } 对stuInfo进行删除 public void Delete(StuInfo stuInfo) { db.Delete(stuInfo); } 这条语句是之前已经插入过的 StuInfo stuinfo = new StuInfo { StuAge = 18, StuNo = &

求100以内素数的5中基本方法及其优化

求100以内素数的5中基本方法及其优化方法1 基本做法 错解比较:进入了小循环:有时加pass也可以.错解:这里的print也同样注意不要写到循环内. 注释:1.两种条件运用:为合数.2.以上错误点.方法二 注释:1.条件运用,质数除了2都是奇数,因为偶数都能被除了自身外的2整除.改进自12.偶数除了2都不是质数.3.第二个for写的是到开方的奇数.4.奇数含有质数和非质数.偶数除了2一定不是质数.所以先剥离了偶数. 方法三:使用列表 注释:1.break continue pass2.质数i依

Linq To Sql中实现Left Join与Inner Join使用Linq语法与lambda表达式

当前有两个表,sgroup与sgroupuser,两者通过gKey关联,而sgroup表记录的是组,而sgroupuser记录是组中的用户,因此在sgroupuser中不一定有数据.需要使用Left Join获取数据: Linq语法如下: var sg = (from g in dc.sgroup join gu in dc.sgroupuser on g.gKey equals gu.gKey into l from lgu in l.DefaultIfEmpty() select new {

linq to sql中修改连接字符串

如果在类库中在添加linq to sql并连接完数据库服务器后会自动生成settings.settings文件,app.config文件用于存储连接字符串(图一) 如要修改连接字符串要修改哪个还是要全部修改呢?经过我研究发现最简单只需要修改dbml一个文件即可,因为三者是关联的,dbml修改后其他两个文件会相应的修改,但是这是有顺序的:dbml.settings.settings和app.config,修改其中一个连接字符串会将之后文件中的连接字符串同步.否则逆向修改会麻烦一些比如修改了app.

sql Server 查询方法的优化

在使用SQL语句查询数据库记录时,如果要查询相同的内容,有着不同的多种方法. 仍然,尽管使用多种方法可以得到相同的结果,但是,如果您使用不同的方法,在执行效益上是截然不同的.因此,我们得仔细考虑,如果要查询相同结果,该使用哪种语句,执行效益比较好. 这就是SQL语句的优化. 以下优化语句,针对My Sql数据库. 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导

LINQ To SQL &amp;&amp; Lambda 使用方法小结 (转)

1. 查询Student表中的所有记录的Sname.Ssex和Class列.select sname,ssex,class from studentLinq: from s in Students    select new {        s.SNAME,        s.SSEX,        s.CLASS    } Lambda: Students.Select( s => new {        SNAME = s.SNAME,SSEX = s.SSEX,CLASS = s.C

LinQ to Sql中的增删改查

第一种方法:1:增加 修改 删除2:查询第二种方法:1:查询所有的数据2:查询指定的数据(筛选)3:添加数据4:删除数据 总结:在第二种方法中 添加 删除 修改 都要用.SubmitChanges()方法向数据库提交数据 原文地址:http://blog.51cto.com/11871779/2084127