Linq杂谈之 — 再谈Linq性能问题

       由于我用Linq的时间并不是很长,所以以下内容如有任何不当之处,还烦请高手给予指正,本人将不胜感激。

       前段时间一个项目中用到了Linq,所以铺天盖地的在网上查找资料,并摸索并尝试着在使用Linq开发。 当然网上诸位对Linq的优缺点把持不一,说Linq好的兄弟们大有一切皆Linq的趋势,说Linq不好的朋友们呢,一方面可能对Linq不是很理解,所以干脆直接将Linq抛弃之。我个人觉得这两种都是过于极端的表现,我们完全可以选择Linq给我们带来的高效率开发的优点,抛弃在开发过程Linq所带来的负面效应。至于怎么做呢,以下是个人愚见:

       1、 Linq 查询篇

       使用Linq所提供的查询功能是很爽的一件事情,如何爽,请看下面的例子:

       查询一个表中的数据,返回泛型实体:

代码
public static List<IPInfo> getTop10Data() 
{
   
using (IpInfoDataContext db = new IpInfoDataContext())
   {
    db.Log 
= Console.Out;
    var query 
= from p in db.IPInfo select p;
    var query1 
= query.Take(10).ToList();
    Console.WriteLine(db.Log);
    
return query1;
    }
}

 输入Code:

 代码

public static void ConsolData()
        {
            List
<IPInfo> list = BLL.IpInfo_BLL.getTop10Data();
            Console.WriteLine(
"\n");
            Console.WriteLine(
"****** Begin Select ************************************************");
            
foreach (IPInfo q in list)
            {
                Console.WriteLine(
"--------------" + q.IPid + "-------------------");
                Console.WriteLine(q.IPCity);
                Console.WriteLine(q.IPFrom);
                Console.WriteLine(q.IPTo);
                Console.WriteLine(q.IPFromNumber);
                Console.WriteLine(q.IPLocation);
            }
            Console.WriteLine(
"****** End Select ************************************************");
        }

 如此一来则可以直接操作泛型的实体了,那比较一下,以前是怎么样返回泛型实体的呢:

 代码

using (SqlDataReader reader = SQLHelper.ExecuteReader(SQLHelper.conStrings, CommandType.Text, "select top(10) * from IPInfo"))
            {
                List
<LinqModel.IPInfo> list = new List<LinqModel.IPInfo>();
                
while (reader.Read())
                {
                    LinqModel.IPInfo model 
= new LinqModel.IPInfo();
                    model.IPCity 
= reader["IPCity"].ToString();
                    model.IPFrom 
= reader["IPFrom"].ToString();
                    model.IPFromNumber 
= reader["IPFromNumber"].ToString();
                    model.IPid 
= long.Parse(reader["IPid"].ToString());
                    model.IPLocation 
= reader["IPLocation"].ToString();
                    model.IPTo 
= reader["IPTo"].ToString();
                    model.IPToNumber 
= reader["IPToNumber"].ToString();
                    list.Add(model);
                }
                
return list;
            }

比较之后,Linq是不是简单很多,当然这里的Linq的ToList()只是一个方面了,还有ToArray、ToDictionary等,至于其他几种怎么用,由于并不是本文的重点,所以这里就不再敖述,网上资料很多,Google一下便知。

当然在开发过程中,很多情况下查询时针对多张表进行的,这个时候我们采用上述的写法就很容易产生问题了,推荐下面这种写法:

 代码

        public static IQueryable getDatabyIndex(int startIndex, int endIndex)
        {
            var query 
= from p in datacontext.IPInfo
                        join c 
in datacontext.Carton_m on p.IPid equals c.IPid
                        orderby p.IPid descending
                        select 
new
                        {
                            p.IPid,
                            p.IPFrom,
                            p.IPTo,
                            p.IPLocation,
                            p.IPCity,
                            p.IPToNumber,
                            p.IPFromNumber,
                            c.webfor
                        };

            
return query.Skip(startIndex).Take(endIndex);

        }

      当然如果多张表的话只要将其他表也拖到当前的datacontext的DBML的页面中,在查询语句中join一下就可以了,并关联一下连接条件,这里之所推荐这种写法,就像我们写Sql Code一样需要什么字段就查询什么字段,而不要一概的Select *,当然这种写法效率高于前者,详见http://blogs.msdn.com/ricom/archive/2007/06/29/dlinq-linq-to-sql-performance-part-3.aspx

      还有一句代码query.Skip(startIndex).Take(endIndex),这个给我们的分页将带来怎样的便捷呀,那么我们来看下生成的SQL代码:

 

很显然,我用的是MSSql2005 那么他就采用Row_Number函数进行分页,我原来用MsSql2000测试过,Linq会自动用Top方式的查询为我们分页,可以说很智能。

当然这些只是Linq的查询功能为我们带来便捷的一小部分而已,其他还有:

(1)Linq已成为编程语言的一个组成部分,在编写程序时可以得到很好的编译时语法检查,丰富的元数据,智能感知、静态类型等强类型语言的好处。

(2)可以使用Linq日志很方便的检查生成的SQL代码,便于用户掌控Linq最终将查询代码转换成怎么样的SQL语句。

(3)并且它同时还使得查询可以方便地对内存中的信息进行查询而不仅仅只是外部数据源。

       当然以上这些只是Linq在查询部分为我们带来的优点。

       2、Linq 添加篇

其实Linq的添加方法(InsertOnSubmit)非常的简单,只要传入一个实体,或者几个参数之后便可以直接调用InsertOnSubmit这个方法,如下:

 

代码
public static void InsertModel(LinqModel.DML.IPInfo model)
        {
            
using (dbmIPInfoDataContext InsertDataContext = new dbmIPInfoDataContext())
            {
              InsertDataContext.IPInfo.InsertOnSubmit(model);
                InsertDataContext.SubmitChanges(System.Data.Linq.ConflictMode.ContinueOnConflict);
            }

        }

当然如果遇到导入Excel这样的需求,一次性要插入很多条数据的情况下,Linq还提供了InsertAllOnSubmit(IEnumerable<Entities>)这个方法,我自己并没有测试效率,只是粗略的Google了一下,有测试说插入10W行数据:

          SqlCommand.Excutive() 执行T-SQL耗时为: 58s

          Linq.InsertAllOnSubmit() 耗时为: 62s

有时间要测试一下这些数据的准确性哈 。

         3、Linq 更新篇

Linq为我们提供的更新操作也是非常简单的,如下Code:

 

代码
 public static void Update(int IPId,string IPCity)
        {
            
using (dbmIPInfoDataContext UpdateDataContext = new dbmIPInfoDataContext())
            {
                LinqModel.DML.IPInfo model 
= UpdateDataContext.IPInfo.Single(IPInfo => IPInfo.IPid == IPId);
                model.IPCity 
= IPCity;
                UpdateDataContext.SubmitChanges(System.Data.Linq.ConflictMode.ContinueOnConflict);
            }
        }

这样看是简单的,但是在这里Linq为我们提供了三种并发操作的选择:

 (1)、RefreshMode.OverwriteCurrentValues //// 放弃当前更新,所有更新以原先更新为准

 (2)、RefreshMode.KeepCurrentValues // 放弃原先更新,所有更新以当前更新为准

 (3)、RefreshMode.KeepChanges// 原先更新有效,冲突字段以当前更新为准

当然至于如何处理这三种操作并非本文重点,如想更加深入理解请Google。

     4、Linq 删除篇

Linq的删除操作就更简单了:

代码
 public static void DelteModel()
        {
            
using (dbmIPInfoDataContext DeleteDataContext = new dbmIPInfoDataContext())
            {
                LinqModel.DML.IPInfo model 
= DeleteDataContext.IPInfo.First(IPInfo => IPInfo.IPToNumber == "TestIPToNumber" && IPInfo.IPCity == "上海");
                DeleteDataContext.IPInfo.DeleteOnSubmit(model);
                DeleteDataContext.SubmitChanges();
            }
        }

      

       5、Linq 总结篇

        以上这些内容,我想很多人是明了的,这只是Linq to Sql的基本操作而已,根据我在之前的项目的经验总结如下:

        (1)、DataContext要及时的释放,别要忘记了我们还有数据库缓冲池。

        (2)、时刻注意你在查询的时候生成的SQL代码,否则你的一些误操作可能导致Linq先将所有数据加载到内存,然后进行符合条件的筛选,这样一来麻烦就大了。

        (3)、复杂的增,删,改,查不建议用Linq,用了反而会降低系统性能,我们不能为了用Linq而用Linq,重要的是需要结合系统的实际情况,适当选择对数据库操作方式。 

        (4)、新事物的出现,肯定是为了补充旧事物的所缺少的地方,当然新事物也可能缺乏成熟,这得由我们发现并指正,新的事物才能不断完善。

        

原文地址:https://www.cnblogs.com/yangtongnet/p/1741123.html