c# - 使用 Linq to Entity 搜索大数据导致内存使用率高

标签 c# asp.net entity-framework linq


我开发了一个 ASP.NET MVC Web 应用程序并使用 Linq to Entity
我在内存使用方面遇到了麻烦

这是我的代码:

//Search for about 0.6 million transaction data
var presQuery=(from A in db.TransDetail
               where A.TRAN_DATE.CompareTo("2015/02/01")>=0 && A.TRAN_DATE.CompareTo("2015/02/28")<=0
               group A by A.MBR_ID into grp
               select new {
                MBR_ID=grp.Key,
                Price=grp.Sum(s=>s.Price)}).ToList();

//Search for about 0.6 million transaction data
var preVQuery=(from A in db.TransDetail
               where A.TRAN_DATE.CompareTo("2015/01/01")>=0 && A.TRAN_DATE.CompareTo("2015/01/31")<=0
               group A by A.MBR_ID into grp
               select new {
                MBR_ID=grp.Key,
                Price=grp.Sum(s=>s.Price)}).ToList();

int[] rankValue=new int(){2000,1000,500,250,100};
TransDetailViewModel model;
List<TransDetailViewModel> ls=new List<TransDetailViewModel>();
double CountRatio;
int TotalPrice;
int TotalCnt;




//start calculate 
for(int i=0;i<5;i++){
    for(int j=0;j<5;j++){
    if (i < 5  && j < 5)
    {
        var query1 = presQuery.Where(w => w.Price >= rankValue[i]);
        var query2 = prevQuery.Where(w => w.Price >= rankValue[j]);
        var query3 = from q1 in query1
                     join q2 in query2 on q1.MBR_ID equals q2.MBR_ID
                     select q1;
        TotalCnt = query3.Count();
        TotalPrice = Convert.ToInt32(query3.Sum(s => s.Price));
        CountRatio = (Convert.ToDouble(query1.Count()) / Convert.ToDouble(query2.Count())) * 100;
        model = new TransDetailViewModel()
        {
            RankLevel = "R" + i.ToString() + j.ToString(),
            CountRatio = CountRatio,
            TotalCount = TotalCnt,
            TotalPrice = TotalPrice
        };
        ls.Add(model);
        }      

    }   
}

以上代码会导致四个人同时开始搜索时应用内存增加到1G的问题。
有没有更高效的解决方法?

最佳答案

在使用 linq 时有一个概念叫做物化,一些像“ToList”这样的命令会导致你的查询“物化”,这意味着,数据将从数据库中获取到内存中,现在看看这段代码

//Search for about 0.6 million transaction data
var presQuery=(from A in db.TransDetail
               where A.TRAN_DATE.CompareTo("2015/02/01")>=0 && A.TRAN_DATE.CompareTo("2015/02/28")<=0
               group A by A.MBR_ID into grp
               select new {
                MBR_ID=grp.Key,
                Price=grp.Sum(s=>s.Price)}).ToList();

“ToList”具体化了查询,所以如果这个查询实际上加载了 60 万行......你只是在这里炸毁了你的内存(我什至没有提到第二个查询是相同的,所以你加载了相同的数据两次),因此只需从查询末尾删除“ToList”即可解决这部分代码之前的内存问题。

现在,对于第二部分,您从双 for 循环开始。当您看到 for 循环与查询代码混合在一起时,您会发现您遗漏了 Select、SelectMany、Join 或 GroupBy 等命令的一些巧妙用法。您永远不需要循环来进行查询。

那些循环将成为一个问题,因为现在我们删除了“ToList”并且我们的查询没有具体化,在 for 循环中调用“Count()”将导致代码多次访问数据库,这很有趣问题是因为运行此代码所需的时间大约是从服务器到数据库的 ping 乘以 for 循环中的迭代次数,因此如果您的数据库是本地的,它运行速度很快,但是当您将其部署到生产环境时,很慢!我们需要摆脱 for 循环。 (我没时间了,所以我现在不打算这样做)

最后,如果你的最终结果有很多行,在获取数据的过程中没有任何变化会让你的应用程序使用更少的内存,唯一的补救办法是让你的最终结果变小 paging your data with skip and take

关于使用存储过程的最后一个评论,procs 很好,因为它们保证数据库只会被命中一次,它在设计用于执行此类计算的数据库上运行,最重要的是好处(恕我直言) 您可以更好地控制查询,linq to entities/sql 在执行复杂查询时会生成非常奇怪且有时无效的 sql

关于c# - 使用 Linq to Entity 搜索大数据导致内存使用率高,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33867919/

相关文章:

c# - DataGridView 绑定(bind)

c# - 将点击事件添加到以编程方式添加的菜单项

c# - 即使位图设置为 Graphics.Clear(Color.Transparent),为什么调整大小时图像周围会出现黑色背景

c# - 使用 C# 将 UTF-8 转换为 Unicode

asp.net - asp.net ajax 刷新后的 Cufon.refresh

javascript - ASP.NET 检查数据库中是否存在电子邮件的最佳方法

ios - 上传图像时对象引用未设置为 object.postmethod POST 文件名文件的实例,但**与 Android 代码一起正常工作**

sql-server - 使用 EF Core 2.1 和 SQL Server 进行正确的并发处理

c# - 允许用户在应用程序中嵌入原始 sql 查询是一种好习惯吗?

c# LINQ Take 用于内部查询