You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用EF Core 5与FileHelpers导入900条CSV数据速度过慢问题求助

CSV导入性能过慢优化方案

核心问题根因

当前代码的耗时99%来自循环内的重复数据库查询与单次提交:

  • 每次循环都执行3次独立数据库查询(球员查重、机构查询、球队查询),600条数据就会产生至少1800次数据库请求,大量时间浪费在网络IO与数据库连接建立上
  • 若AddPlayer、AddTeam等方法内部每次都调用SaveChanges(),还会额外产生数百次事务提交开销
  • EF Core默认的实时变更跟踪会在批量操作时产生大量无用计算,进一步拖慢速度

优化方案

1. 预热缓存减少数据库查询

导入前先把所有需要用到的对照数据一次性加载到内存,避免循环内查库:

// 提前加载所有球员查重字段到HashSet,查重仅查内存
var existingPlayers = db.Players.Select(p => new { p.FirstName, p.Surname, p.Year, p.EmailAddress })
    .AsNoTracking()
    .ToHashSet(p => (p.FirstName, p.Surname, p.Year, p.EmailAddress));

// 提前加载机构映射字典
var orgMap = refTable.GetAllRefOrginizations()
    .AsNoTracking()
    .ToDictionary(o => o.Name, o => o.Id);

// 提前加载球队映射字典
var teamMap = team.GetAllTeams()
    .AsNoTracking()
    .ToDictionary(t => t.Name, t => t.Id);

// 待新增列表,统一批量提交
var toAddOrgs = new List<Ref_Orginzation>();
var toAddTeams = new List<Team>();
var toAddPlayers = new List<Player>();

2. 循环内仅做内存计算

var engine = new FileHelperEngine<PlayerImportCSVModel>();
var result = engine.ReadFile(FileName);

foreach (var item in result)
{
    // 内存查重,无IO开销
    var playerKey = (item.FirstName, item.LastName, Convert.ToInt32(item.BirthYear), item.Email);
    if (existingPlayers.Contains(playerKey))
        continue;

    var player = new Player
    {
        FirstName = item.FirstName,
        Surname = item.LastName,
        PlayerLevel = item.Level,
        Year = Convert.ToInt32(item.BirthYear),
        IsActive = true,
        EmailAddress = item.Email,
        IsDeleted = false,
        CreatedBy = "System Import",
        CreatedDate = DateTime.Now,
        Gender = item.Gender == "M" ? 1 : 2
    };

    // 处理机构
    if (!orgMap.TryGetValue(item.Association, out var orgId))
    {
        var newOrg = new Ref_Orginzation
        {
            Name = item.Association,
            IsActive = true,
            IsDeleted = false, // 注意原代码这里写的是true,属于逻辑bug,新机构不能标记为删除
            CreatedBy = "System Import",
            CreatedDate = DateTime.Now
        };
        toAddOrgs.Add(newOrg);
        // 临时加入字典,避免重复新增同名称机构
        orgMap[item.Association] = newOrg.Id;
        orgId = newOrg.Id;
    }
    player.OrginizationId = orgId;

    // 处理球队
    if (!teamMap.TryGetValue(item.Team, out var teamId))
    {
        var newTeam = new Team
        {
            Name = item.Team,
            IsActive = true,
            IsDeleted = false,
            CreatedBy = "System Import",
            CreatedDate = DateTime.Now
        };
        toAddTeams.Add(newTeam);
        teamMap[item.Team] = newTeam.Id;
        teamId = newTeam.Id;
    }
    player.TeamId = teamId;

    toAddPlayers.Add(player);
}

3. 统一批量提交

// 关闭EF Core变更追踪提升性能
db.ChangeTracker.AutoDetectChangesEnabled = false;

// 批量新增,单次SaveChanges
db.Ref_Orginzations.AddRange(toAddOrgs);
db.Teams.AddRange(toAddTeams);
db.Players.AddRange(toAddPlayers);
db.SaveChanges();

// 恢复原有配置
db.ChangeTracker.AutoDetectChangesEnabled = true;

如果需要进一步提速,可以引入对应的EF Core批量插入扩展库,600条数据总耗时可以控制在1秒以内。


内容的提问来源于stack exchange,提问作者dotnetdevcsharp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 07:06:04