EntityFramework Core有许多新的特性,其中一个重要特性即是批量操做。git
批量操做意味着不须要为每次Insert/Update/Delete操做发送单独的命令,而是在一次SQL请求中发送批量组合指令。github
批处理是期待已久的功能,社区屡次提出要求。如今EFCore支持开箱即用确实很棒,能够提升应用程序的性能和速度。sql
下面以常见的批量插入为例,使用SQL Server Profiler 观察实际产生并执行的SQL语句。数据库
// category table中添加了3条记录并执行保存 using (var c= new SampleDBContext()) { c.Categories.Add(new Category() { CategoryID = 1, CategoryName = "Clothing" }); c.Categories.Add(new Category() { CategoryID = 2, CategoryName = "Footwear" }); c.Categories.Add(new Category() { CategoryID = 3, CategoryName = "Accessories" }); c.SaveChanges(); }
当执行SaveChanges(), 从SQL Profiler追溯到的SQL:ide
exec sp_executesql N'SET NOCOUNT ON; INSERT INTO [Categories] ([CategoryID], [CategoryName]) VALUES (@p0, @p1),(@p2, @p3),(@p4, @p5);', N'@p0 int,@p1 nvarchar(4000),@p2 int,@p3 nvarchar(4000),@p4 int,@p5 nvarchar(4000)', @p0=1,@p1=N'Clothing',@p2=2,@p3=N'Footwear',@p4=3,@p5=N'Accessories'
如你所见,批量插入没有产生3个独立的语句,而是被组合为一个传参存储过程脚本(用列值做为参数);若是使用EF6执行相同的代码,则在SQL Server Profiler中将看到3个独立的插入语句 。下面左右是EFCore、EF6批量插入的对比截图:性能
通过验证:EFCore批量更新、批量删除功能,EFCore均发出了使用sp_executesql存储过程+批量参数构建的SQL脚本。ui
起关键做用的 sp_executesql存储过程: 能够屡次执行的语句或批处理 (可带参)this
-- Syntax for SQL Server, Azure SQL Database, Azure SQL Data Warehouse, Parallel Data Warehouse sp_executesql [ @stmt = ] statement [ { , [ @params = ] N'@parameter_name data_type [ OUT | OUTPUT ][ ,...n ]' } { , [ @param1 = ] 'value1' [ ,...n ] } ]
注意官方限制: spa
The amount of data that can be passed by using this method is limited by the number of parameters allowed. SQL Server procedures can have, at most, 2100 parameters. Server-side logic is required to assemble these individual values into a table variable or a temporary table for processing. // SQL存储过程最多可以使用2100个参数code
SqlServer sp_executesql存储过程最多支持2100个批量操做造成的列值参数,因此遇到很大数量的批量操做,EFCore SqlProvider会帮咱们将批量操做分块传输,
这也是咱们在实际大批量使用时看到分块发送的缘由。
同时EFCore开放了【配置关系型数据库批量操做大小】:
protected override void OnConfiguring(DbContextOptionsBuilder optionbuilder) { string sConnString = @"Server=localhost;Database=EFSampleDB;Trusted_Connection=true;"; optionbuilder.UseSqlServer(sConnString , b => b.MaxBatchSize(1)); // 批量操做的SQL语句数量,也可设定为1禁用批量插入 }
① EFCore 相比EF6,已经支持批量操做,能有效提升应用程序的性能
② EFCore的批量操做能力,由对应的DataBaseProvider支撑(Provider实现过程跟背后的存储载体密切相关)
对于SQL关注这个存储过程sp_executesql , 官方明文显示批量操做的列值参数最多2100 个,这个关键因素决定了在大批量操做的时候 依旧会被分块传输。
③ 另一个批量操做的方法,这里也点一下:构造Rawsql【EFCore支持Rawsql】。
sqlite不支持存储过程,为完成批量插入提升性能,可采用此方案。
var insertStr = new StringBuilder(); insertStr.AppendLine("insert into ProfileUsageCounters (profileid,datetime,quota,usage,natureusage) values"); var txt = insertStr.AppendLine(string.Join(',', usgaeEntities.ToList().Select(x => { return $"({x.ProfileId},{x.DateTime},{x.Quota},{x.Usage},{x.NatureUsage})"; }).ToArray())); await _context.Database.ExecuteSqlCommandAsync(txt.ToString());