• Entity Framework Code First 在Object Join Linq查询时出现全表查询的语句。


    最近一个项目,使用微软的Entity Framework的ORM框架的项目,部署到现场后,出现了系统缓慢,多个客户端的内存溢出崩溃的问题。

    打开了SQL Server Profiler(SQL Server Profiler的简单使用)排查,发现有全表查询的语句,这表中有上万条数据,所以客户端查询后内存溢出了。

    从代码中排查是否有直接全表查询的语句,结果未找到,后来在网上搜索到Linq to Object 连接(join) Linq to Entity时可能会引起全表查询。(https://www.cnblogs.com/gxlinhai/p/4263393.html)

    所以这里也创建了一个demo做了进一步的了解。

    此Demo 使用Entity Framework的ORM框架,只需要配置数据库连接,能自动生成数据库,并创建一些数据。

    表有Entity和Foo两个表,其中Foo表中有Entity表的外键。

    打开SQL Server Profiler检测生成的语句。

    测试一,用IEnumerable来连表查询。

                    IEnumerable<Foo> foos = db.Foos; 
                    var objectNames = (from foo in foos
                                       join en in db.Entitys
                                       on foo.EntityId equals en.EntityId
                                       select foo.Name).ToList();

    之后在SQL Server Profiler中监测到如下语句:

    SELECT 
        [Extent1].[EntityId] AS [EntityId], 
        [Extent1].[Name] AS [Name], 
        [Extent1].[Notes] AS [Notes]
        FROM [dbo].[Entities] AS [Extent1]
    

     出现了Entity表全表查询的语句。

    测试二, 用var来连表查询。

                    var foos = db.Foos; 
                    var objectNames = (from foo in foos
                                       join en in db.Entitys
                                       on foo.EntityId equals en.EntityId
                                       select foo.Name).ToList();
    

     在SQL Server Profiler中,监测到的语句如下

    SELECT 
        [Extent1].[Name] AS [Name]
        FROM  [dbo].[Foos] AS [Extent1]
        INNER JOIN [dbo].[Entities] AS [Extent2] ON [Extent1].[EntityId] = [Extent2].[EntityId]
    

     没有出现全表查询的语句。

    测试三,用IQueryable来连表查询

    IQueryable<Foo> foos = db.Foos; 
    var objectNames = (from foo in foos
                      join en in db.Entitys
                       on foo.EntityId equals en.EntityId
                       select foo.Name).ToList();
    

     在SQL Server Profiler中,监测到的语句如下

    SELECT 
        [Extent1].[Name] AS [Name]
        FROM  [dbo].[Foos] AS [Extent1]
        INNER JOIN [dbo].[Entities] AS [Extent2] ON [Extent1].[EntityId] = [Extent2].[EntityId]
    

     没有出现全表查询的语句。

    测试四:结合别人说的代码,修改如下

     List<MyObject> objectList = new List<MyObject>();
                    objectList.Add(new MyObject { Identity = 1, Name = "Jack", Age = 30 });
                    objectList.Add(new MyObject { Identity = 2, Name = "Sam", Age = 28 });
                    objectList.Add(new MyObject { Identity = 3, Name = "Lucy", Age = 23 });
    
                    var objectNames = (from foo in objectList
                                       join en in db.Entitys
                                       on foo.Identity equals en.EntityId
                                       select foo.Name).ToList();
    

     在SQL Server Profiler中,监测到的语句如下

    SELECT 
        [Extent1].[EntityId] AS [EntityId], 
        [Extent1].[Name] AS [Name], 
        [Extent1].[Notes] AS [Notes]
        FROM [dbo].[Entities] AS [Extent1]
    

     又出现了Entity全表查询的语句。

    结论:

    测试1:返回结果为IEnumerable时,有可能数据已经缓存到内存里了,作为了object,这样再linq查询时,不会重新调整sql语句,导致了连接表全表查询后在内存中过滤。

    测试2、3: IQueryable在连表查询时,最后会重新生成sql语句来查询。var默认为DbSet,DbSet也会重新生成sql语句来查询。

    测试4: 直接证明了object与linq查询,导致查询语句会变成全表查询。

    Demo见如下:

    百度网盘:https://pan.baidu.com/s/1cDEIS2

    提取密码:qwnb

  • 相关阅读:
    Socket编程
    jdbc03 使用servlet实现
    el和jstl
    java03变量和基本数据类型
    java02
    ssh整合
    U1总结
    多线程
    spring07 JDBC
    cocos2dx中的三种基本的数据类型
  • 原文地址:https://www.cnblogs.com/sdner/p/8043232.html
Copyright © 2020-2023  润新知