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