除了你的內存管理的問題,你將不得不使用分頁這個不好的時候。運行分頁查詢將在服務器上變得昂貴。你不需要頁面。只需迭代查詢結果(即不要調用ToList()或ToArray())。
另外,當分頁時,您必須向查詢添加排序,否則SQL可能會返回重疊的行,或者存在間隙。請參閱SQL Server,例如:https://docs.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql EF Core不強制執行此操作,因爲某些提供程序可能會保證分頁查詢始終以相同順序讀取行。
這裏的EF核心的(1.1 .NET核心)通過一個巨大的結果集犁地不增加內存使用情況的示例:
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System;
using System.ComponentModel.DataAnnotations.Schema;
namespace efCoreTest
{
[Table("SomeEntity")]
class SomeEntity
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime CreatedOn { get; set; }
public int A { get; set; }
public int B { get; set; }
public int C { get; set; }
public int D { get; set; }
virtual public Address Address { get; set; }
public int AddressId { get; set; }
}
[Table("Address")]
class Address
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
}
class Db : DbContext
{
public DbSet<SomeEntity> SomeEntities { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=.;Database=efCoreTest;Integrated Security=true");
}
}
class Program
{
static void Main(string[] args)
{
using (var db = new Db())
{
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
db.Database.ExecuteSqlCommand("alter database EfCoreTest set recovery simple;");
var LoadAddressesSql = @"
with N as
(
select top (10) cast(row_number() over (order by (select null)) as int) i
from sys.objects o, sys.columns c, sys.columns c2
)
insert into Address(Id, Line1, Line2, Line3)
select i Id, 'AddressLine1' Line1,'AddressLine2' Line2,'AddressLine3' Line3
from N;
";
var LoadEntitySql = @"
with N as
(
select top (1000000) cast(row_number() over (order by (select null)) as int) i
from sys.objects o, sys.columns c, sys.columns c2
)
insert into SomeEntity (Name, Description, CreatedOn, A,B,C,D, AddressId)
select concat('EntityName',i) Name,
concat('Entity Description which is really rather long for Entity whose ID happens to be ',i) Description,
getdate() CreatedOn,
i A, i B, i C, i D, 1+i%10 AddressId
from N
";
Console.WriteLine("Generating Data ...");
db.Database.ExecuteSqlCommand(LoadAddressesSql);
Console.WriteLine("Loaded Addresses");
for (int i = 0; i < 10; i++)
{
var rows = db.Database.ExecuteSqlCommand(LoadEntitySql);
Console.WriteLine($"Loaded Entity Batch {rows} rows");
}
Console.WriteLine("Finished Generating Data");
var results = db.SomeEntities.AsNoTracking().Include(e => e.Address).AsEnumerable();
int batchSize = 10 * 1000;
int ix = 0;
foreach (var r in results)
{
ix++;
if (ix % batchSize == 0)
{
Console.WriteLine($"Read Entity {ix} with name {r.Name}. Current Memory: {GC.GetTotalMemory(false)/1024}kb GC's Gen0:{GC.CollectionCount(0)} Gen1:{GC.CollectionCount(1)} Gen2:{GC.CollectionCount(2)}");
}
}
Console.WriteLine($"Done. Current Memory: {GC.GetTotalMemory(false)/1024}kb");
Console.ReadKey();
}
}
}
}
輸出
Generating Data ...
Loaded Addresses
Loaded Entity Batch 1000000 rows
Loaded Entity Batch 1000000 rows
. . .
Loaded Entity Batch 1000000 rows
Finished Generating Data
Read Entity 10000 with name EntityName10000. Current Memory: 2854kb GC's Gen0:7 Gen1:1 Gen2:0
Read Entity 20000 with name EntityName20000. Current Memory: 4158kb GC's Gen0:14 Gen1:1 Gen2:0
Read Entity 30000 with name EntityName30000. Current Memory: 2446kb GC's Gen0:22 Gen1:1 Gen2:0
. . .
Read Entity 9990000 with name EntityName990000. Current Memory: 2595kb GC's Gen0:7429 Gen1:9 Gen2:1
Read Entity 10000000 with name EntityName1000000. Current Memory: 3908kb GC's Gen0:7436 Gen1:9 Gen2:1
Done. Current Memory: 3916kb
注意,過多的存儲器的另一常見原因EF Core中的消耗是查詢的「Mixed client/server evaluation」。有關詳細信息,請參閱文檔以及如何禁用自動客戶端查詢評估。
你是什麼意思的「數據」?如果您對某種DTO對象使用投影查詢,或者不使用跟蹤查詢,則「DbContext」不會在內部存儲任何內容。也不要使用'ToList','ToArray'等。簡單地列舉結果。 –
我已經使用'.AsNoTracking()'關閉了對查詢的更改跟蹤。我也刪除了'ToArray()',但垃圾收集器仍然沒有釋放任何上下文。 http://prntscr.com/g4q0h3至於我的意思是數據,我的意思是我正在尋找從數據庫中獲取記錄到C#模型中暫時使用然後處理掉。我有一種感覺,由於遞歸循環,對象不會從內存中移除? –
不要使用EF Core,這不是合適的情況。使用原始查詢,您可以隨時讀取數據的子集,即使用數據讀取器 – Tseng