通过EF以面向对象的方式操作数据库带来了一定的便利性,但是某些情况下不宜采用EF否则会遇到性能瓶颈。目前遇到的问题主要包括两个方面:批量的DB操作、从DB带出大数量计算再持久化。
1、批量的DB操作
EF对批量插入、更新等操作会通过构造多条SQL的方式传输给DB执行,当量大的时候会带来传输及执行(执行方式甚至语句可优化)上的时间浪费。
(1)示例
foreach (var photo in photos) { //添加样本照片记录 var samplePhoto = new SamplePhoto() { SamplePhotoId = CommonBll.PR_GetSysKey(efContext, "SamplePhoto", "SamplePhotoId", venderId), PhotoId = photo.PhotoId, SourceId = sampleSourceInfo.SourceId, IsAllot = 0, JoinTime = now, VenderId = venderId }; samplePhotoRepository.Add(samplePhoto);
(2)执行情况
foreach里的add产生多条执行的SQL
INSERT [dbo].[SamplePhoto]([SamplePhotoId], [PhotoId], [SourceId], [IsAllot], [JoinTime], [Height], [VenderId], [Width]) VALUES (@0, @1, @2, @3, @4, NULL, @5, NULL) -- @0: '10001303' (Type = Int32) -- @1: '54A7075D-1797-438A-B068-981D89B78AEB' (Type = String, Size = -1) -- @2: '10001044' (Type = Int32) -- @3: '0' (Type = Int32) -- @4: '2018/10/9 7:19:10' (Type = DateTime2) -- @5: '1000' (Type = Int32) -- 正在 2018/10/9 7:21:10 +08:00 执行 -- 已在 46 毫秒内完成,结果为: 1 INSERT [dbo].[SamplePhoto]([SamplePhotoId], [PhotoId], [SourceId], [IsAllot], [JoinTime], [Height], [VenderId], [Width]) VALUES (@0, @1, @2, @3, @4, NULL, @5, NULL) -- @0: '10001304' (Type = Int32) -- @1: '63B78093-A0F1-4E2B-8973-BED22164EAF1' (Type = String, Size = -1) -- @2: '10001044' (Type = Int32) -- @3: '0' (Type = Int32) -- @4: '2018/10/9 7:19:10' (Type = DateTime2) -- @5: '1000' (Type = Int32) -- 正在 2018/10/9 7:21:10 +08:00 执行 -- 已在 34 毫秒内完成,结果为: 1 INSERT [dbo].[SamplePhoto]([SamplePhotoId], [PhotoId], [SourceId], [IsAllot], [JoinTime], [Height], [VenderId], [Width]) VALUES (@0, @1, @2, @3, @4, NULL, @5, NULL) -- @0: '10001305' (Type = Int32) -- @1: '8F40A68C-0207-4000-BAB0-654ACCCDEA30' (Type = String, Size = -1) -- @2: '10001044' (Type = Int32) -- @3: '0' (Type = Int32) -- @4: '2018/10/9 7:19:10' (Type = DateTime2) -- @5: '1000' (Type = Int32) -- 正在 2018/10/9 7:21:10 +08:00 执行 -- 已在 38 毫秒内完成,结果为: 1
2、从DB带出大数量计算再持久化
大数量量从DB传递到应用,计算后再从应用传递到DB,需要耗费大量的网络资源,时间会消耗在传输上。
var sampleboxs = boxs.Where(T => T.SamplePhotoId == photo.SamplePhotoId).ToList(); if (sampleboxs != null) { foreach (var box in sampleboxs) { var samplePhotoBox = new SamplePhotoBox() { //BoxId = CommonBll.PR_GetSysKey(efContext, "SamplePhotoBox", "BoxId", venderId), SamplePhotoId = samplePhoto.SamplePhotoId, XMax = box.XMax, XMin = box.XMin, YMax = box.YMax, YMin = box.YMin, SkuCode = box.SkuCode }; samplePhotoBoxRepository.Add(samplePhotoBox); } }
从DB带出sampleboxs再逐个遍历计算后Add到另一张表,如果sampleboxs的量足够大的时候,这个逻辑的执行时间会花费几十秒、几分钟…
3、替代方式
对于EF有可能出现性能瓶颈的地方可通过执行“存储过程”或“参数化执行原生SQL”解决。
SqlParameter[] paras = new SqlParameter[3]; paras[0] = new SqlParameter("@inspectId", inspectId); paras[1] = new SqlParameter("@userId", userId); paras[2] = new SqlParameter("@venderId", venderId); var result = efContext.Database.SqlQuery<string>( "EXEC dbo.PR_NewSkuSetSample @inspectId,@userId,@venderId", paras).First();