上一篇文章中,我们比较出单表插入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. multi selects & mutually exclusive

    multi selects & mutually exclusive 互斥 selects import React, { useState, // useEffect, // useRef, ...

  2. js 拖拽排序

    See alsoe: https://www.runoob.com/html/html5-draganddrop.html https://developer.mozilla.org/zh-CN/do ...

  3. WebView & WKWebView & UIWebView

    WebView & WKWebView & UIWebView WebView WKWebView https://developer.apple.com/documentation/ ...

  4. react 异步的setState

    import React from "react"; class App extends React.Component { state = { a: 0 }; component ...

  5. PAUL ADAMS ARCHITECT:薪资追不上房价美一半家庭难买房

    尽管上一年度美国经济遭受重创,但美国房价依旧持续蹿扬,据最新调查显示,美国大部分地区的房价已经到了一般家庭无法负担的水准. 美国房价上涨持续强劲,主要受益美国人居家办公需求(受大环境影响,目前美国有7 ...

  6. OAuth:每次授权暗中保护你的那个“MAN”

    摘要:OAuth是一种授权协议,允许用户在不将账号口令泄露给第三方应用的前提下,使第三方应用可以获得用户在某个web服务上存放资源的访问权限. 背景 在传统模式下,用户的客户端在访问某个web服务提供 ...

  7. 开源OA办公平台功能介绍:应用市场-固定资产管理(一)功能设计

    概述 应用市场-固定资产管理,是用来维护管理企业固定资产的一个功能.其整个功能包括对固定资产的台账信息.领用.调拨.借用.维修.盘点.报废等一整个生命周期的动态管理过程.力求客户安装就可以使用. 本应 ...

  8. 痞子衡嵌入式:系统时钟配置不当会导致i.MXRT1xxx系列下OTFAD加密启动失败

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是系统时钟配置不当会导致i.MXRT1xxx系列下OTFAD加密启动失败问题. 我们知道,i.MXRT1xxx家族早期型号(RT1050/ ...

  9. 小白养成记——JavaWeb之文件的上传

    文件的上传推荐使用commons的fileupload组件来完成.该组件还依赖于io包,因此需要用到两个jar包: commons-fileupload-X.X.jar commons-io-X.X. ...

  10. zabbix Python3管理

    import requests import json import os # user config here ip = '192.168.52.130' user = "root&quo ...