遍历每个记录实体框架服务器端分页

问题描述 投票:0回答:1

通过分页遍历所有记录 有一张表大约有 7650000 条记录,我想遍历所有记录 做一些处理。我正在使用 Entity Framework Query 并使用服务器端分页的概念 查询看起来像

        int totalBatches= 7650;
        int batchSize =1000;
        for (int i = 0; i <= totalBatches+1; i++)
        {
            int firstId = 0, lastDbId = 0;
            Console.WriteLine($"Processing  Batch {i.ToString()} of {totalBatches}");
            var batch = context.TableName
                                .Include(x => x.RelatedTable)
                                .OrderBy(x => x.Id)
                            .Skip(i).Take(batchSize).ToList();
            if (batch.Count() <= 0)
            {
                Console.WriteLine($"SKIPPING LOOP SINCE NO RECORDS EXISTS");
                break;
            }
            
            foreach (var entry in batch)
            {
            //processing each records
            }
        }

看起来执行已完成,没有任何错误,但是当我在那里检查已处理记录的摘要时 记录上有些不匹配。我花了大约 6 个多小时才完成脚本的执行 数据库是 Mysql,我使用 Pomelo.EntityFrameworkCore.MySql 驱动作为依赖

所以想知道分页逻辑是否正确 有没有更好的方法来进行服务器端分页?还是这种方法会导致数据丢失?

c# mysql entity-framework pagination
1个回答
0
投票

这种方法有两种变慢的方式。


Skip(a).Take(b)
慢是因为它实际上强制 DB 准备
a + b
行发送,然后忽略
a
行,这使得后续查询越来越慢,导致 O(n^2) 复杂度。不幸的是,要使此 DB 操作成为 O(n),您需要一种不同的分页方式。这是关于该主题的非常好的读物:https://learn.microsoft.com/en-us/ef/core/querying/pagination


这是假设您使用的是检测更改的默认方式,如果您没有为您的实体实施

INotifyPropertyChanging
INotifyPropertyChanged
并且使您的 DBContext 不使用快照
.

这还假设您的代码执行此操作:

  1. 开始交易
  2. 获取批次
  3. 批量处理实体
  4. 电话
    .SaveChanges()
  5. 重复 3. 和 4. 直到你遍历所有实体
  6. 结束交易

默认情况下,

DBContext
必须跟踪它提供给您的所有实体(在您的情况下通过
.ToList()
)。
DBContext
不幸的是无法知道您何时完成对任何特定实体的更改,因此它必须跟踪 every single entity.

因此,这些实体的内部集合只会越来越大,每次调用 SaveChanges() 时,它都必须检查当前批次中的实体以及所有先前批次中的所有实体 ,导致检查更改的 O(n^2) 复杂度以及 O(n) 内存复杂度 (!!)

为了解决这个问题,您可以在每个

context.ChangeTracker.Clear();
之后调用
context.SaveChanges();
以有效地告诉上下文您不会对前一批中的实体进行任何更改。


作为第三种选择,如果实体处理本身很简单(比如只在所有行的列中添加一些数字)并且您使用的是最新版本的 EF,您可以尝试使用批量更新来使整个事情运行数据库。在此处阅读有关

ExecuteUpdate
的信息:https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-7.0/whatsnew

© www.soinside.com 2019 - 2024. All rights reserved.