• 7行代码看EntityFramework是如何运行


    这段时间在项目中运用Entity Framework作为底层数据交互框架。一个字,爽。不仅提高了开发效率,省了很多代码,而且数据库也规范了很多。按照网上的一些教程初步学习,然后实际运用了,再结合MVC ,开发一个模块的增删改查,那真是一个爽歪歪。但是,随着项目不断完善,数据表越来越多,关联性也越来越复杂,问题也逐渐露出水面。首先最大的问题是数据查询慢。有个影响点是Linq里的Count(),查阅了网上许多资料,都没有好的解决方法。这个问题暂时不说,如果那位大师有良策,还不忘赐教。

    影响查询慢主要问题在于数据查询,说白了不了解EF是如何执行sql查询的,什么时候进行sql查询?以什么方式进行sql查询的?

    我做了一个demo,以微软的Northwind作为数据库,有个Customers表和Orders表,Orders表里有个字段CustomerID,是Customers表的外键。代码如下:

    1 NorthwindEntities db = new NorthwindEntities();
    2 var query = db.Customers.AsEnumerable();
    3 for (int idx = 0; idx < 2; idx++)
    4 {
    5      var customer = query.ElementAt(idx);
    6       var order = customer.Orders.FirstOrDefault();
    7        if (order != null)
    8               Console.WriteLine(order.OrderID);
    9  }

    在跟踪代码时,同时将SQL Server Profiler打开。代码执行到2行,sql跟踪器并没有执行sql语句。当执行第5行时,sql跟踪器有了反应。

    sql 是查询了customers表。再往下执行到第6行时,

    根据外键customerid 去查询orders订单。如此。每循环一次。数据库就会执行2次查询。如果有查询结果有20条,就会有40次查询,如果关联的表越多。查询的次数就会越多。

    系统查询能不慢吗。

    解决方法:

     1             NorthwindEntities db = new NorthwindEntities();
     2             ////取消EF的延迟加载
     3             db.Configuration.LazyLoadingEnabled = false;
     4             ////一次性查询出customers和Orders数据,并利用ToList()放入到内存中
     5             var query = db.Customers.Include("Orders").ToList();
     6             for (int idx = 0; idx < 2; idx++)
     7             {
     8                 var customer = query.ElementAt(idx);
     9                 var order = customer.Orders.FirstOrDefault();
    10                 if (order != null)
    11                     Console.WriteLine(order.OrderID);
    12             }

    取消EF的延迟加载。利用Include()将所需要对象一次性查询出来。并利用ToList()将数据存入内存中。

    这是优化后的sql运行跟踪。我们会发现,只实现了一次查询,sql语句用了left join的方式将数据一次性查询出来。每次循环也只会访问内存中。

    总结:

    从这4行代码中,我们发现

    1.AsEnumerable()和 AsQueryable() 是延迟执行,当具体使用对象时才会执行sql;ToList() 在使用时就已经执行,并数据存入内存中。
    2.EF 本身默认的是延迟加载,每个关联的查询,每次循环的查询都是要执行数据库的。取消延迟加载,利用Include方法,可以一次性将所有数据查询出来。
    以上观点纯属个人经验总结,欢迎各位大鸟发表看法,小菜向大家学习了。
     

    【编后语】

    博文发表后,笔者看到许多同行的讨论,也学到不少东西。笔者这里申明,自己并非黑EF。正是看到了EF的强大,才开始使用它。但是,任何东西都要学懂。就好比笔者来说,之前的用法,导致一个10行的列表,数据库查询就执行了好几百次。虽然这是在开发中问题不是很明显,但是一旦正式使用,这绝对是一个隐藏的炸弹。

    EF很强大,但是,不懂它心的人,只会让自己伤心!

    与广大程序员共勉!

    【再编后语】

    笔者很不平。多数同行并没有看懂这篇博文的意思。循环2次是模拟展示列表。例如,我有表格要展示这个客户的订单,没有分页。按照前面那种方案

     customer.Orders.FirstOrDefault();
    这个客户有多少可订单,数据库执行多少次。
    而第二种方案:
    var query = db.Customers.Include("Orders").ToList();
    数据库只执行一次就可以。展示表格的时候都是从内存中获取。
    这就是是个明显数据库性能的问题。笔者虚心向大家讨教!
  • 相关阅读:
    BZOJ4827: [Hnoi2017]礼物(FFT 二次函数)
    洛谷P3586 [POI2015]LOG(贪心 权值线段树)
    BZOJ4373: 算术天才⑨与等差数列(线段树 hash?)
    cf711D. Directed Roads(环)
    洛谷P3313 [SDOI2014]旅行(树链剖分 动态开节点线段树)
    洛谷P2045 方格取数加强版(费用流)
    cf900D. Unusual Sequences(容斥 莫比乌斯反演)
    agc007D
    hdu 4287Intelligent IME(简单hash)
    Python Post and Get 登陆web后台系统并抓取页面
  • 原文地址:https://www.cnblogs.com/ttrjba/p/3974055.html
Copyright © 2020-2023  润新知