当结果存储在数组中时,linq会加载多少记录?

eln*_*ani 0 c# linq linq-to-sql

我的数据库中有600万条记录,我想加载所有这个查询:

var query=(from p in behzad.test
          select p).ToArray();
Run Code Online (Sandbox Code Playgroud)

我可以加载吗?

xan*_*tos 5

极不可能......你会遇到多个"墙".

首先......假设每条记录只是一个ID ...只是以最好的方式存储6亿个ID,它是6亿*4字节= 2.4gb.但我不认为你的对象太小了.然后有对象的引用...每个引用是64位的8个字节...

http://codeblog.jonskeet.uk/2011/04/05/of-memory-and-strings/ here Skeet计算出一个64位对象使用的最小内存是24字节...所以14.4gb(它没有"T包括对对象的引用,该new object[size]之前GC.GetTotalMemory(true)).在这个空间中,您可以放置​​两个int而不会使对象变大(例如ID,另一个int字段)(在同一页面中,搜索表格TwoInt32s).

然后存在LINQ-to-SQL在加载时复制记录(一个副本转到其对象跟踪器)的问题.您可以使用https://msdn.microsoft.com/en-us/library/system.data.linq.datacontext.objecttrackingenabled.aspx禁用此功能.

然后每个阵列有一个最大2GB的内存限制...是一个8字节(64位)的引用数组,它将是一个数组的大约2.6亿条记录.使用.NET 4.0以64位删除它:https://msdn.microsoft.com/en-us/library/hh285054.aspx

然后还有另一个问题ToArray():构建数组它通过加倍,使用2的幂(4个元素,8个元素,16,32,64,128 ... 1024 ... 1024*1024个元素,...)所以在构建一个包含6亿个引用的数组之前(仅为4.8 gb,但是包含在24个字节/元素中,所以我们不计算它),它将构建一个512万个元素(4 gb)的临时数组,那么1024万个元素之一(8 gb,其中3.2无用),然后它将把102400万个元素中的一个调整为6亿个.

所以在ToArray()你结束之前你会:

  • 14.4 gb的行
  • 对于102400万个元素的引用数组,为8.0 gb
  • 对于600万个元素的引用数组,5.4 gb

所以至少你需要14.4 + 8.0 + 5.4 = 27.8 gb ... 2 int秒......这是一个"理论上的最小值".我会将它增加至少50-100%,使其成为"实际最小值".你还在int为每条记录处理2个:-)

现在......阿列克谢建议使用struct.struct它们的优点是它们不需要参考,它们的大小几乎与它们使用的大小完全相同.

您可以将查询更改为:

var query = (from p in behzad.test select p)
               .Select(p => new MyStruct { ID = p.ID, Foo = p.Foo })
               .ToArray();
Run Code Online (Sandbox Code Playgroud)

现在每个元素都是8字节大,所以你需要

  • 对于102400万个元素的引用数组,为8.0 gb
  • 对于600万个元素的引用数组,5.4 gb

总计13.4 gb.

请注意,使用类似于string你内部元素的引用类型仍然是一个很大的不行(它会占用太多内存).