上一篇文章中,我们比较出单表插入9999行数据,Dapper > EfCore > Freesql。在本文中,我们来看看级联插入

构建9999行数据

List<Entity> datas = new List<Entity>();
for (int i = 0; i < 9999; i++)
{
var item = new Entity
{
No = i + 1,
Col1 = Guid.NewGuid().ToString("N"),
Col2 = Guid.NewGuid().ToString("N"),
Col3 = Guid.NewGuid().ToString("N"),
Col4 = Guid.NewGuid().ToString("N"),
Col5 = Guid.NewGuid().ToString("N"),
Col6 = Guid.NewGuid().ToString("N"),
Col7 = Guid.NewGuid().ToString("N"),
Col8 = Guid.NewGuid().ToString("N"),
Col9 = Guid.NewGuid().ToString("N"),
Col10 = Guid.NewGuid().ToString("N"),
};
item.EntitySubs.Add(new EntitySub
{
Col1 = Guid.NewGuid().ToString("N"),
Col2 = Guid.NewGuid().ToString("N"),
Col3 = Guid.NewGuid().ToString("N"),
Col4 = Guid.NewGuid().ToString("N"),
Col5 = Guid.NewGuid().ToString("N"),
Col6 = Guid.NewGuid().ToString("N"),
Col7 = Guid.NewGuid().ToString("N"),
Col8 = Guid.NewGuid().ToString("N"),
Col9 = Guid.NewGuid().ToString("N"),
Col10 = Guid.NewGuid().ToString("N"),
});
item.EntitySubs.Add(new EntitySub
{
Col1 = Guid.NewGuid().ToString("N"),
Col2 = Guid.NewGuid().ToString("N"),
Col3 = Guid.NewGuid().ToString("N"),
Col4 = Guid.NewGuid().ToString("N"),
Col5 = Guid.NewGuid().ToString("N"),
Col6 = Guid.NewGuid().ToString("N"),
Col7 = Guid.NewGuid().ToString("N"),
Col8 = Guid.NewGuid().ToString("N"),
Col9 = Guid.NewGuid().ToString("N"),
Col10 = Guid.NewGuid().ToString("N"),
});
item.EntitySubs.Add(new EntitySub
{
Col1 = Guid.NewGuid().ToString("N"),
Col2 = Guid.NewGuid().ToString("N"),
Col3 = Guid.NewGuid().ToString("N"),
Col4 = Guid.NewGuid().ToString("N"),
Col5 = Guid.NewGuid().ToString("N"),
Col6 = Guid.NewGuid().ToString("N"),
Col7 = Guid.NewGuid().ToString("N"),
Col8 = Guid.NewGuid().ToString("N"),
Col9 = Guid.NewGuid().ToString("N"),
Col10 = Guid.NewGuid().ToString("N"),
});
datas.Add(item);
}

Dapper:

static void AddDataByDapperCascade(List<Entity> datas)
{
#region 数据格式转换
var dataTemporarys = new List<EntityTemporary>();
var dataSubTemporarys = new List<EntitySubTemporary>(); for (int i = 0, length = datas.Count; i < length; i++)
{
var item = datas[i];
var newItem = new EntityTemporary
{
No = item.No,
Col1 = item.Col1,
Col2 = item.Col2,
Col3 = item.Col3,
Col4 = item.Col4,
Col5 = item.Col5,
Col6 = item.Col6,
Col7 = item.Col7,
Col8 = item.Col8,
Col9 = item.Col9,
Col10 = item.Col10,
Position = i + 1
};
dataTemporarys.Add(newItem);
dataSubTemporarys.AddRange(item.EntitySubs.Select(x => new EntitySubTemporary
{
Col1 = x.Col1,
Col2 = x.Col2,
Col3 = x.Col3,
Col4 = x.Col4,
Col5 = x.Col5,
Col6 = x.Col6,
Col7 = x.Col7,
Col8 = x.Col8,
Col9 = x.Col9,
Col10 = x.Col10,
Position = i + 1
}));
}
#endregion Stopwatch sw = new Stopwatch();
sw.Start();
using (var conn = new SqlConnection(connString))
{
conn.Open();
string createTable = @"create table #EntityTemp ([No] int, Col1 varchar(50), Col2 varchar(50), Col3 varchar(50), Col4 varchar(50), Col5 varchar(50), Col6 varchar(50), Col7 varchar(50), Col8 varchar(50), Col9 varchar(50), Col10 varchar(50), Position int);";
string createTable2 = @"create table #EntitySubTemp (Col1 varchar(50), Col2 varchar(50), Col3 varchar(50), Col4 varchar(50), Col5 varchar(50), Col6 varchar(50), Col7 varchar(50), Col8 varchar(50), Col9 varchar(50), Col10 varchar(50), Position int);";
string insertTable = "INSERT INTO #EntityTemp ([No], Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9, Col10, Position) VALUES (@No, @Col1, @Col2, @Col3, @Col4, @Col5, @Col6, @Col7, @Col8, @Col9, @Col10, @Position)";
string insertTable2 = "INSERT INTO #EntitySubTemp (Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9, Col10, Position) VALUES (@Col1, @Col2, @Col3, @Col4, @Col5, @Col6, @Col7, @Col8, @Col9, @Col10, @Position)";
string saveSql = @"DECLARE @inserted0 TABLE ([Id] int, [Position] [int]);
MERGE into TestAddSortByDapper t
USING #EntityTemp AS s ON 1=0 WHEN NOT MATCHED THEN
INSERT([No], [Col1], [Col2], [Col3], [Col4], [Col5], [Col6], [Col7], [Col8], [Col9], [Col10])
VALUES(s.[No], s.[Col1], s.[Col2], s.[Col3], s.[Col4], s.[Col5], s.[Col6], s.[Col7], s.[Col8], s.[Col9], s.[Col10])
OUTPUT INSERTED.[Id], s.Position INTO @inserted0;
INSERT INTO TestAddSortByDapperSub ([Id2], [Col1], [Col2], [Col3], [Col4], [Col5], [Col6], [Col7], [Col8], [Col9], [Col10])
SELECT i.id AS id2, s.Col1, s.Col2, s.Col3, s.Col4, s.Col5, s.Col6, s.Col7, s.Col8, s.Col9, s.Col10
FROM #EntitySubTemp s
INNER JOIN @inserted0 i ON s.[Position] = i.[Position];";
conn.Execute(createTable + " \r\n " + createTable2);
conn.Execute(insertTable, dataTemporarys);
conn.Execute(insertTable2, dataSubTemporarys);
conn.Execute(saveSql);
}
sw.Stop();
Console.WriteLine($"通过 Dapper和临时表进行insert操作 毫时{sw.ElapsedMilliseconds}");
}

执行结果总结

数据库执行结果也和我们sql代码一样,dapper也是用insert into table() values () 的方法一行行加代码,执行时间大概在6-7秒。

EfCore:

由于efcore本身就支持级联增加,所有代码比较简单

public class TestContext : DbContext
{
public DbSet<Entity> Entity { get; set; }
public DbSet<EntitySub> EntitySub { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(connString);
}
}
[Table("TestAddSortByEfCore")]
public class Entity
{
public int Id { get; set; }
public int No { get; set; }
public string Col1 { get; set; }
public string Col2 { get; set; }
public string Col3 { get; set; }
public string Col4 { get; set; }
public string Col5 { get; set; }
public string Col6 { get; set; }
public string Col7 { get; set; }
public string Col8 { get; set; }
public string Col9 { get; set; }
public string Col10 { get; set; } [ForeignKey("Id2")]
public virtual ICollection<EntitySub> EntitySubs { get; set; } = new HashSet<EntitySub>();
} [Table("TestAddSortByEfCoreSub")]
public class EntitySub
{
public int Id { get; set; }
public int Id2 { get; set; }
public string Col1 { get; set; }
public string Col2 { get; set; }
public string Col3 { get; set; }
public string Col4 { get; set; }
public string Col5 { get; set; }
public string Col6 { get; set; }
public string Col7 { get; set; }
public string Col8 { get; set; }
public string Col9 { get; set; }
public string Col10 { get; set; }
}
static void AddDataByEfCoreCascade(List<Entity> datas)
{
int r1 = 0;
Stopwatch sw = new Stopwatch();
sw.Start();
using (var db = new TestContext())
{
db.Entity.AddRange(datas);
r1 = db.SaveChanges();
}
sw.Stop();
Console.WriteLine($"通过 EfCore 导入数据{r1}行 毫时{sw.ElapsedMilliseconds}");
}

执行结果总结

-- 数据库实际执行语句
(@p0 nvarchar(4000),...,@p461 int)
SET NOCOUNT ON;
DECLARE @inserted0 TABLE ([Id] int, [_Position] [int]);
MERGE [TestAddSortByEfCore]
USING (
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, 0),...,(@p451, @p452, @p453, @p454, @p455, @p456, @p457, @p458, @p459, @p460, @p461, 41)
) AS i ([Col1], [Col10], [Col2], [Col3], [Col4], [Col5], [Col6], [Col7], [Col8], [Col9], [No], _Position) ON 1=0
WHEN NOT MATCHED THEN
INSERT ([Col1], [Col10], [Col2], [Col3], [Col4], [Col5], [Col6], [Col7], [Col8], [Col9], [No])
VALUES (i.[Col1], i.[Col10], i.[Col2], i.[Col3], i.[Col4], i.[Col5], i.[Col6], i.[Col7], i.[Col8], i.[Col9], i.[No])
OUTPUT INSERTED.[Id], i._Position INTO @inserted0;
SELECT [t].[Id] FROM [TestAddSortByEfCore] t INNER JOIN @inserted0 i ON ([t].[Id] = [i].[Id]) ORDER BY [i].[_Position];

(@p11 nvarchar(4000),...,@p471 nvarchar(4000),@p472 int)
SET NOCOUNT ON;
DECLARE @inserted0 TABLE ([Id] int, [_Position] [int]);
MERGE [TestAddSortByEfCoreSub]
USING (
VALUES (@p11, @p12, @p13, @p14, @p15, @p16, @p17, @p18, @p19, @p20, @p21, 0),...,(@p462, @p463, @p464, @p465, @p466, @p467, @p468, @p469, @p470, @p471, @p472, 41)
) AS i ([Col1], [Col10], [Col2], [Col3], [Col4], [Col5], [Col6], [Col7], [Col8], [Col9], [Id2], _Position) ON 1=0
WHEN NOT MATCHED THEN
INSERT ([Col1], [Col10], [Col2], [Col3], [Col4], [Col5], [Col6], [Col7], [Col8], [Col9], [Id2])
VALUES (i.[Col1], i.[Col10], i.[Col2], i.[Col3], i.[Col4], i.[Col5], i.[Col6], i.[Col7], i.[Col8], i.[Col9], i.[Id2])
OUTPUT INSERTED.[Id], i._Position INTO @inserted0;
SELECT [t].[Id] FROM [TestAddSortByEfCoreSub] t INNER JOIN @inserted0 i ON ([t].[Id] = [i].[Id]) ORDER BY [i].[_Position];

从结果我们可以看到,efcore使用的是Merge方式执行,总耗时14-15秒,这个在性能上是不能接受的。

ADO.Net BulkCopy:

static void AddDataByBulkCopyTemporary2(List<Entity> datas)
{
Stopwatch sw = new Stopwatch();
sw.Start();
int r = 0; using (SqlConnection cn = new SqlConnection(connString))
{
cn.Open(); DataTable entityTable = new DataTable();
entityTable.Columns.Add("No");
entityTable.Columns.Add("Col1");
entityTable.Columns.Add("Col2");
entityTable.Columns.Add("Col3");
entityTable.Columns.Add("Col4");
entityTable.Columns.Add("Col5");
entityTable.Columns.Add("Col6");
entityTable.Columns.Add("Col7");
entityTable.Columns.Add("Col8");
entityTable.Columns.Add("Col9");
entityTable.Columns.Add("Col10");
entityTable.Columns.Add("Position"); DataTable entitySubTable = new DataTable();
entitySubTable.Columns.Add("Col1");
entitySubTable.Columns.Add("Col2");
entitySubTable.Columns.Add("Col3");
entitySubTable.Columns.Add("Col4");
entitySubTable.Columns.Add("Col5");
entitySubTable.Columns.Add("Col6");
entitySubTable.Columns.Add("Col7");
entitySubTable.Columns.Add("Col8");
entitySubTable.Columns.Add("Col9");
entitySubTable.Columns.Add("Col10");
entitySubTable.Columns.Add("Position");
for (int i = 0; i < datas.Count; i++)
{
var item = datas[i];
DataRow dr = entityTable.NewRow();
dr[0] = item.No;
dr[1] = item.Col1;
dr[2] = item.Col2;
dr[3] = item.Col3;
dr[4] = item.Col4;
dr[5] = item.Col5;
dr[6] = item.Col6;
dr[7] = item.Col7;
dr[8] = item.Col8;
dr[9] = item.Col9;
dr[10] = item.Col10;
dr[11] = i + 1;
entityTable.Rows.Add(dr);
foreach (var sub in item.EntitySubs)
{
var subDr = entitySubTable.NewRow();
subDr[0] = sub.Col1;
subDr[1] = sub.Col2;
subDr[2] = sub.Col3;
subDr[3] = sub.Col4;
subDr[4] = sub.Col5;
subDr[5] = sub.Col6;
subDr[6] = sub.Col7;
subDr[7] = sub.Col8;
subDr[8] = sub.Col9;
subDr[9] = sub.Col10;
subDr[10] = i + 1;
entitySubTable.Rows.Add(subDr);
}
} string createTable = @"create table #EntityTemp ([No] int, Col1 varchar(50), Col2 varchar(50), Col3 varchar(50), Col4 varchar(50), Col5 varchar(50), Col6 varchar(50), Col7 varchar(50), Col8 varchar(50), Col9 varchar(50), Col10 varchar(50), Position int);";
string createTable2 = @"create table #EntitySubTemp (Col1 varchar(50), Col2 varchar(50), Col3 varchar(50), Col4 varchar(50), Col5 varchar(50), Col6 varchar(50), Col7 varchar(50), Col8 varchar(50), Col9 varchar(50), Col10 varchar(50), Position int);";
cn.Execute(createTable);
cn.Execute(createTable2);
using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(cn))
{
sqlBulkCopy.BatchSize = entityTable.Rows.Count;
sqlBulkCopy.BulkCopyTimeout = 1800;
sqlBulkCopy.DestinationTableName = "#EntityTemp"; sqlBulkCopy.ColumnMappings.Add("No", "No");
sqlBulkCopy.ColumnMappings.Add("Col1", "Col1");
sqlBulkCopy.ColumnMappings.Add("Col2", "Col2");
sqlBulkCopy.ColumnMappings.Add("Col3", "Col3");
sqlBulkCopy.ColumnMappings.Add("Col4", "Col4");
sqlBulkCopy.ColumnMappings.Add("Col5", "Col5");
sqlBulkCopy.ColumnMappings.Add("Col6", "Col6");
sqlBulkCopy.ColumnMappings.Add("Col7", "Col7");
sqlBulkCopy.ColumnMappings.Add("Col8", "Col8");
sqlBulkCopy.ColumnMappings.Add("Col9", "Col9");
sqlBulkCopy.ColumnMappings.Add("Col10", "Col10");
sqlBulkCopy.ColumnMappings.Add("Position", "Position");
sqlBulkCopy.WriteToServer(entityTable);
}
using (SqlBulkCopy sqlBulkCopy2 = new SqlBulkCopy(cn))
{
sqlBulkCopy2.BatchSize = entitySubTable.Rows.Count;
sqlBulkCopy2.BulkCopyTimeout = 1800;
sqlBulkCopy2.DestinationTableName = "#EntitySubTemp"; sqlBulkCopy2.ColumnMappings.Add("Col1", "Col1");
sqlBulkCopy2.ColumnMappings.Add("Col2", "Col2");
sqlBulkCopy2.ColumnMappings.Add("Col3", "Col3");
sqlBulkCopy2.ColumnMappings.Add("Col4", "Col4");
sqlBulkCopy2.ColumnMappings.Add("Col5", "Col5");
sqlBulkCopy2.ColumnMappings.Add("Col6", "Col6");
sqlBulkCopy2.ColumnMappings.Add("Col7", "Col7");
sqlBulkCopy2.ColumnMappings.Add("Col8", "Col8");
sqlBulkCopy2.ColumnMappings.Add("Col9", "Col9");
sqlBulkCopy2.ColumnMappings.Add("Col10", "Col10");
sqlBulkCopy2.ColumnMappings.Add("Position", "Position");
sqlBulkCopy2.WriteToServer(entitySubTable);
} string sql = @"DECLARE @inserted0 TABLE ([Id] int, [Position] [int]);
MERGE into TestAddSortByBulkCopy t
USING #EntityTemp AS s ON 1=0 WHEN NOT MATCHED THEN
INSERT ([Col1], [Col2], [Col3], [Col4], [Col5], [Col6], [Col7], [Col8], [Col9], [Col10], [No])
VALUES (s.[Col1], s.[Col2], s.[Col3], s.[Col4], s.[Col5], s.[Col6], s.[Col7], s.[Col8], s.[Col9], s.[Col10], s.[No])
OUTPUT INSERTED.[Id], s.Position INTO @inserted0;
insert into TestAddSortByBulkCopySub ([Id2], [Col1], [Col2], [Col3], [Col4], [Col5], [Col6], [Col7], [Col8], [Col9], [Col10])
select i.id AS id2, s.Col1, s.Col2, s.Col3, s.Col4, s.Col5, s.Col6, s.Col7, s.Col8, s.Col9, s.Col10
from #EntitySubTemp s
inner join @inserted0 i on s.[Position] = i.[Position] ";
r = cn.Execute(sql);
}
sw.Stop();
Console.WriteLine($"通过 BulkCopy 导入数据{r}行 毫时{sw.ElapsedMilliseconds}");
}

执行结果总结

两篇文章进行总结,dapper采用insert into table() values () 方式一行行加数据,但性能上还是挺不错的;efcore当数据大于两行则采用Merge方式,性能上略低于dapper,级联上性能比较差了;freesql采用insert into table() values (), (), ()一次性增加多行,单表查询性能是最差的,估计上代码上问题而不是sql语句问题;Bulkcopy的性能是最好的,毕竟他是ADO.net针对大量数据而设计的。

Dapper, Ef core, Freesql 插入大量数据性能比较(二)的更多相关文章

  1. Dapper, Ef core, Freesql 插入大量数据性能比较(一)

    需求:导入9999行数据时Dapper, Ef core, Freesql 谁的性能更优,是如何执行的,级联增加谁性能更佳. 确认方法:sql server 的 sys.dm_exec_query_s ...

  2. c# 国内外ORM 框架 dapper efcore sqlsugar freesql hisql sqlserver数据常规插入测试性能对比

    c# 国内外ORM 框架 dapper efcore sqlsugar freesql hisql sqlserver数据常规插入测试性能对比对比 在6.22 号发布了 c# sqlsugar,his ...

  3. EF Core利用Transaction对数据进行回滚保护

    What? 首先,说一下什么是EF Core中的Transaction Transaction允许以原子方式处理多个数据库操作,如果事务已提交,则所有操作都应用于数据库,如果事务回滚,则没有任何操作应 ...

  4. EF Core 使用编译查询提高性能

    今天,我将向您展示这些EF Core中一个很酷的功能,通过使用显式编译的查询,提高查询性能. 不过在介绍具体内容之前,需要说明一点,EF Core已经对表达式的编译使用了缓存:当您的代码需要重用以前执 ...

  5. Sqlite3插入大量数据性能优化

    近期做的一个项目数据量很大.文本数据有30多M.这样就遇到一个问题.插入数据库时很慢. 这里记录下,优化方法很easy. 原文地址:http://blog.csdn.net/qqmcy/article ...

  6. IOC+EF+Core项目搭建IOC注入及框架(二)

    配置ServiceCollection /// <summary> /// 表示IServiceCollection的扩展 /// </summary> public stat ...

  7. 深入理解 EF Core:EF Core 读取数据时发生了什么?

    阅读本文大概需要 11 分钟. 原文:https://bit.ly/2UMiDLb 作者:Jon P Smith 翻译:王亮 声明:我翻译技术文章不是逐句翻译的,而是根据我自己的理解来表述的.其中可能 ...

  8. 深入理解 EF Core:使用查询过滤器实现数据软删除

    原文:https://bit.ly/2Cy3J5f 作者:Jon P Smith 翻译:王亮 声明:我翻译技术文章不是逐句翻译的,而是根据我自己的理解来表述的.其中可能会去除一些本人实在不知道如何组织 ...

  9. 【.NET 6】使用EF Core 访问Oracle+Mysql+PostgreSQL并进行简单增改操作与性能比较

     前言 唠嗑一下.都在说去O或者开源,但是对于数据库选型来说,很多人却存在着误区.例如,去O,狭义上讲,是去Oracle数据库.但是从广义上来说,是去Oracle公司产品或者具有漂亮国垄断地位和需要商 ...

随机推荐

  1. Google can't be accessed again, today is shit day

    Google can't be accessed again, today is shit day 2019.11.28 12:00~20:56 holy shit (pile of poop) Go ...

  2. EventBus / Event Bus

    EventBus / Event Bus EventEmitter / Event Emitter https://greenrobot.org/eventbus/documentation/ htt ...

  3. Error Code: 1452 Cannot add or update a child row: a foreign key constraint fails

    错误: Error Code: 1452 Cannot add or update a child row: a foreign key constraint fails 错误产生情景:我向一张带外键 ...

  4. [转]ubuntu系统重新分区、根目录扩容

    原文地址:https://blog.csdn.net/code_segment/article/details/79237500,转载主要方便随时查阅,如有版权要求,请及时联系. gparted是一款 ...

  5. 1079 Total Sales of Supply Chain ——PAT甲级真题

    1079 Total Sales of Supply Chain A supply chain is a network of retailers(零售商), distributors(经销商), a ...

  6. TkMybatis添加对象后返回数据的id

    在实体类的id属性上加上下面的注解 //导入的包import javax.persistence.GeneratedValue; @GeneratedValue(generator = "J ...

  7. 在 Svelte 中使用 CSS-in-JS

    你即便不需要,但你可以. 注意:原文发表于2018-12-26,随着框架不断演进,部分内容可能已不适用. CSS 是任何 Web 应用程序的核心部分. 宽泛而论,如果一个 UI 框架没有内置向组件添加 ...

  8. javascript中的模块系统

    目录 简介 CommonJS和Nodejs AMD异步模块加载 CMD ES modules和现代浏览器 在HTML中使用module和要注意的问题 简介 在很久以前,js只是简单的作为浏览器的交互操 ...

  9. 使用lua-nginx模块实现请求解析与调度

    系统版本及需求: OS:CentOS 7.7.1908 OpenResty:1.15.8.2 目录 描述 安装配置 安装openresty 使用示例 HTTP请求复制 HTTP报文解析 总结 描述 l ...

  10. MongoDB4.2 副本集扫盲说明

    说明: 在扫盲MongoDB相关的一些知识的时候,顺手做下笔记.本文将说明副本集相关的内容.在比较早之前已经对这些有过说明,可以看MongoDB 副本集的原理.搭建.应用.MongoDB中的副本集是一 ...