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());