EF批量插入太慢?那是你的姿势不对

本文探讨了在大规模数据批量插入时,使用EF效率较低的问题,并提供了MySQL的LOAD DATA命令和SQL Server的SqlBulkCopy类作为解决方案。通过转换数据源格式,如CSV和DataTable,实现高效导入。同时,展示了如何将这些方法优雅地集成到EF中,通过依赖注入自动判断数据库类型并执行相应批量插入操作。

大概所有的程序员应该都接触过批量插入的场景,我也相信任何的程序员都能写出可正常运行的批量插入的代码。但怎样实现一个高效、快速插入的批量插入功能呢?

由于每个人的工作履历,工作年限的不同,在实现这样的一个需求时,可能技术选型各有不同,有直接生成insert语句的,有用EF的或者其他的orm框架的。其实不管是手写insert还是使用EF,最终交给数据库执行的还是insert语句。下面是EF批量插入的示例代码:

var list = new List<Student>();
for (int i = 0; i < 100; i++)
{
    list.Add(new Student { CreateTime = DateTime.Now, Name = "zjjjjjj" });
}

await _context.Students.AddRangeAsync(list);
await _context.SaveChangesAsync();

生成的脚本截图如下:

zzz

这种实现方式在数据量100以内时,耗时还算可以。但如果要批量导入的数据达到万级的时候,那耗时简直是灾难。我测试的数据如下(测试数据库为mysql,具体配置不详):

数据量 耗时(s)
10 0.028
1w 3.929
10w 31.280

10w的数据已经耗时超过了30s,我没有勇气测试100w数据的耗时,有兴趣的可以自行测试下。

下面就应该进入正题了,对于较大数据量(1000以上)场景下的批量插入,各个数据库应该都提供了相关的解决方案,由于工作所限,目前笔者仅接触过mysql和mssql。

mysql的实现方案是LOAD DATA命令,此命令接收一个csv文件,然后将文件上传到数据库服务器后,解析数据后插入。好在MySqlConnector提供了相关的封装,不用咱们去熟悉那么复杂的命令参数。

mssql实现的方案是使用SqlBulkCopy类,不过此类仅接收DataTable类型的数据,所以,在批量插入的时候,需要将数据源转换成DataTable。

综上所示,不管是mysql,还是mssql,均需要将数据源转换成指定的格式才可以使用批量导入的功能,所以这一块的主要核心就是转换数据源格式。mysql需要转换成csv,mssql需要转换成DataTable。下面就来一起看看具体的转换的方法。

以下代码是转换csv和DataTable相关方法:

namespace FL.DbBulk
{
    public static class Extension
    {
        /// <summary>
        /// 获取实体影射的表名
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static string GetMappingName(this System.Type type)
        {
            var key = $"batch{type.FullName}";

            var tableName = CacheService.Get(key);
            if (string.IsNullOrEmpty(tableName))
            {
                var tableAttr = type.GetCustomAttribute<TableAttribute>();
                if (tableAttr != null)
                {
                    tableName = tableAttr.Name;
                }
                else
                {
                    tableName = type.Name;
                }
                CacheService.Add(key, tableName);
            }
            return tableName;
        }

        public static List<EntityInfo> GetMappingProperties(this System.Type type)
        {
            var key = $"ICH.King.DbBulk{type.Name}";
            var list = CacheService.Get<List<EntityInfo>>(key);
            if (list == null)
            {
                list = new List<EntityInfo>();
                foreach (var propertyInfo in type.GetProperties())
                {
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值