EFCore批量操作,你真的清楚吗
背景
EntityFramework Core有許多新的特性,其中一個(gè)重要特性便是批量操作。批量操作意味著不需要為每次Insert/Update/Delete操作發(fā)送單獨(dú)的命令,而是在一次SQL請(qǐng)求中發(fā)送批量組合指令。
EFCore批量操作實(shí)踐
批處理是期待已久的功能,社區(qū)多次提出要求。現(xiàn)在EFCore支持開箱即用確實(shí)很棒,可以提高應(yīng)用程序的性能和速度。
1
對(duì)比實(shí)踐
以常見的批量插入為例,使用SQL Server Profiler觀察產(chǎn)生并執(zhí)行的SQL語句。
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();
}
當(dāng)執(zhí)行SaveChanges(), 從SQL Profiler追溯到的SQL:
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'
如你所見,批量插入沒有產(chǎn)生3個(gè)獨(dú)立的語句,而是被組合為一個(gè)傳參存儲(chǔ)過程腳本(用列值作為參數(shù));如果使用EF6執(zhí)行相同的代碼,則在SQL Server Profiler中將看到3個(gè)獨(dú)立的插入語句 。下面是EFCore、EF6批量插入的對(duì)比截圖:
① 就性能和速度而言,EFCore批量插入更具優(yōu)勢(shì)
② 若數(shù)據(jù)庫是針對(duì)云部署,EF6運(yùn)行這些查詢,還將產(chǎn)生額外的流量成本
經(jīng)過驗(yàn)證:EFCore批量更新、批量刪除功能,EFCore均發(fā)出了使用sp_executesql存儲(chǔ)過程+批量參數(shù)構(gòu)建的SQL腳本。
2
深入分析
起關(guān)鍵作用的存儲(chǔ)過程sp_executesql:可以多次執(zhí)行的語句或批處理 (可帶參)
-?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?]?}??
]
注意官方限制:
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存儲(chǔ)過程最多可使用2100個(gè)參數(shù)
3
豁然開朗
SqlServer sp_executesql存儲(chǔ)過程最多支持2100個(gè)批量操作形成的列值參數(shù),所以遇到很大數(shù)量的批量操作,EFCore SqlProvider會(huì)幫我們將批量操作分塊傳輸,這也是我們?cè)趯?shí)際大批量使用時(shí)看到分塊發(fā)送的原因。
EFCore開放了【配置關(guān)系型數(shù)據(jù)庫批量操作大小】:
protected?override?void?OnConfiguring(DbContextOptionsBuilder?optionbuilder){
????string?sConnString?=?@"Server=localhost;Database=EFSampleDB;Trusted_Connection=true;";
????optionbuilder.UseSqlServer(sConnString?,?b?=>?b.MaxBatchSize(1));?
???//?批量操作的SQL語句數(shù)量,也可設(shè)定為1禁用批量插入
}
總結(jié)
① EFCore 相比EF6,已經(jīng)支持批量操作,能有效提高應(yīng)用程序的性能
② EFCore的批量操作能力,由對(duì)應(yīng)的DataBaseProvider支撐(Provider實(shí)現(xiàn)過程跟背后的存儲(chǔ)載體密切相關(guān));關(guān)注SQL存儲(chǔ)過程sp_executesql,官方明文顯示批量操作的列值參數(shù)最多2100個(gè),這個(gè)關(guān)鍵因素決定了在大批量操作的時(shí)候 依舊會(huì)被分塊傳輸。
③ 另外一個(gè)批量操作的方法,這里也點(diǎn)一下:構(gòu)造Rawsql 【EFCore也支持Rawsql】
sqlite不支持存儲(chǔ)過程,為批量插入提高性能,可采用此方案:
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());
+?https://github.com/aspnet/EntityFrameworkCore/issues/6604
+?https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/table-valued-parameters?redirectedfrom=MSDN
總結(jié)
以上是生活随笔為你收集整理的EFCore批量操作,你真的清楚吗的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 使用ASP.NET Core 3.x 构
 - 下一篇: asp.net core 自定义 Pol