大概所有的程序员应该都接触过批量插入的场景,我也相信任何的程序员都能写出可正常运行的批量插入的代码。但怎样实现一个高效、快速插入的批量插入功能呢?
由于每个人的工作履历,工作年限的不同,在实现这样的一个需求时,可能技术选型各有不同,有直接生成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();
生成的脚本截图如下:
这种实现方式在数据量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())
{

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

被折叠的 条评论
为什么被折叠?



