Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance Linq和大数据集的内存/效率_Performance_Linq_Memory - Fatal编程技术网

Performance Linq和大数据集的内存/效率

Performance Linq和大数据集的内存/效率,performance,linq,memory,Performance,Linq,Memory,你知道我的背景吧,我做了十二年的专业程序员。到目前为止,我最好的语言是C,但是我已经做了C、C++和最近的ObjvEC。我在访问数据库中的数据方面做了很多工作,但除了在IOS中,我没有做过像大多数人那样多的UI工作 最近,我开始在C中使用实体框架来完成一项工作,我必须说,我希望我能早点发现它。我不会说这是自切片面包以来最好的东西,但它非常接近。在使用了一段时间后,它让我想到了与所有东西都使用IDBConnections和IDBCommands的老式方法相比的最佳实践和用法 我编写代码的目的是为了

你知道我的背景吧,我做了十二年的专业程序员。到目前为止,我最好的语言是C,但是我已经做了C、C++和最近的ObjvEC。我在访问数据库中的数据方面做了很多工作,但除了在IOS中,我没有做过像大多数人那样多的UI工作

最近,我开始在C中使用实体框架来完成一项工作,我必须说,我希望我能早点发现它。我不会说这是自切片面包以来最好的东西,但它非常接近。在使用了一段时间后,它让我想到了与所有东西都使用IDBConnections和IDBCommands的老式方法相比的最佳实践和用法

我编写代码的目的是为了在绑定的数据网格中列出数据库中用户表的内容,目的是让用户能够执行标准的CRUD操作。我首先制作了一个用户类和一个带有相应实现的IUserManager接口。每个用户都被分配到一个部门,自然也需要一种在部门上执行CRUD的方法,所以我添加了一个department类、一个IDepartmentManager接口和一个实现。我对其进行了设置,以便网格绑定到IUserManager接口上的.GetAll方法的结果上。然后我开始填肚子

我不再需要这些代码了,但我基本上使用IDBConnection通过使用SQL查询的IDBCommand访问数据存储。然后我调用command.ExecuteReader并在IDataReader对象上迭代.Read方法。使用每个列的序号,我提取数据,验证数据,并将其滑入用户类,然后将该类添加到字典中,然后该方法将返回该字典。当然,所有的DB类都是IDisposable的,所以将它们包装在一个using中就可以清理混乱

相当标准的东西,我已经做了无数次了

这时我意识到我从数据库中提取的部门ID不是我想要在网格中显示的。告诉某人‘这家伙在第七部门’不如说‘这家伙在会计部门’有用。因此,我首先尝试修改我的查询以获得departmentId和name,然后将名称存储在用户对象上以供以后显示。然后,我决定给用户一个Department类实例,它将在其生命周期内挂起并填充该实例。就在那时,我把胆量变成了林克

   public Dictionary<int, User> GetAll()
    {
        var result = new Dictionary<int, User>();

        using (var datastore = new myEntities())
        {
            result = (from user in datastore.userInfoes
                       join department in datastore.userDepartmentInfoes on user.departmentID equals department.departmentID
                    select new User()
                    {
                        UserIndex = user.id,
                        FirstName = user.firstName,
                        LastName =  user.lastName,
                        Department = new Department()
                        {
                            DepartmentId = user.departmentID.Value,
                            DepartmentName = department.departmentName,
                                                                                                            },
                        Username =  user.userName,
                    }
                ).ToDictionary(x => x.UserIndex, x => x);
        }

        return result;
    }
这就是我开始思考阅读的地方:可能是过度分析

我的实现将很好地工作。对于一个小的数据集,它甚至可以很好地工作。对于更大的数据集(比如10000个),它甚至可以正常工作。即使你把我目前工作的公司里的每一个人都算上五倍,你的员工也不到一千人

但如果有那么一秒钟我为一家拥有1000万员工的大公司工作呢?这将导致departmentName字符串可能重复数百万次

这也让我想到,与IOS的MVC实现不同的是,这种特殊情况不会查询到足够多的用户来填充屏幕,然后处理分页和其他事情。一旦调用代码刷新了数据绑定,它将一次拉回所有1000万用户并传回集合。那会很慢的

因此,在我的脑海中留下了这样一个想法,即对于较大的数据集,这种方法既慢又低效。不仅如此,事实上,这个数据集可能有200万个“记帐”实例,这将是一个巨大的内存消耗。我们在这里也有点违背了关系数据库的目的,因为用户内部有Department类。在DB中,只有一个departmentId int外键引用另一个表中的条目。只有当您交叉引用另一个表时,并且在任何时候实际上只有一个“会计”字符串时,才会出现链接。在上面的代码中,将有大量的“记帐”字符串四处浮动,等待清理

MVC场景基本上“知道”需要X个条目来填充网格的可视区域。它一次只能从索引Y开始查询X,当用户导航时,它会根据需要查询和显示其他记录。这比查询所有1000万人并让他们在某个地方闲逛要好得多,不管他们是否被展示


正如我所说,我很可能过度分析了这一点。我对linq工作方式的一些假设可能也不正确。但是出于学习的兴趣,我想我不得不问:做这样的事情最好的方法是什么?对于小数据集来说,这种事情可以吗?作为一个MCV实现,整个事情会比拉入整个数据集显示在网格中更好吗?

如果您需要在m中显示整个数据集 埃默里-你将不得不加载它无论如何。我相信你不会在网格中列出10kk用户,对吗?出现的技术是分页。请举例说明

对于departments对象,您的UserInfo是否有部门的外键?如果是这样的话,你应该有userInfo.Department可供你使用,不需要加入

如果将部门数据绑定到网格列,为什么要使用department类型的属性?我假设您的用户类是绑定到UI的东西。将其展平为:

class User
{
 Username 
 UserIndex
 FirstName
 LastName
 DepartmentId
 DepartmentName 
}
GetAll的目的是什么?您返回一个字典,感觉需要按id启用查找。还是使用结果枚举用户

查找时,考虑与数据库进行对话,以在需要时获取单个用户数据。如果下一步有意义,实现缓存

对于枚举,不要返回字典-这是内存中的全部对象,返回IEnumerable和paged?结果或更好的IQueryable,这样调用GetAll不会立即执行sql调用,并且调用代码可以通过添加必要的过滤器来确定调用的范围