我的Linq查询要优化:
var onlineData = (from od in peopleStatus.AsNoTracking().ToList()
let location = (from zone in db.RTLS_ZONEDTLS
where zone.zone_id == od.Person.Zone_ID
select zone.area).AsNoTracking().FirstOrDefault()
let zoneIdsArray = getZoneList((od.ZoneIds.ToArray()))
let fzones = zoneIdsArray.Select(z => z).Take(4)
select new OnlineDataInfoDTO
{
P_ID = od.Person.PERSONID,
T_ID = (int)od.Person.TAGID,
Z_ID = (od.Person.created_time >= startOfThisDay) ? (int)od.Person.Zone_ID : -1,
LOC = (location != null ? location : " "),
STATUS = (od.Person.created_time >= startOfThisDay) ? (int)od.Person.status : 6,
T_BAT_SIG_STR = (int)od.Person.TAG_SIGNALSTRENGTH,
B_BAT_SIG_STR = (int)od.Person.BS_SIGNALSTRENGTH,
T_BAT_STA_VAL = (int)od.Person.TAG_BATTERY_STATUS_VAL,
T_BAT_STA_PERCNT = (int)od.Person.TAG_BATTERY_STATUS_PERCNT,
BS_BAT_STA_VAL = (int)od.Person.BS_BATTERY_STATUS_VAL,
BS_BAT_STA_PER = (int)od.Person.BS_BATTERY_STATUS_PERCNT,
IN_TIME = (od.Person.INTIME).ToString(),
ALL_NOT_TME = (od.Person.ALLISNOTWELLTIME).ToString(),
P_TME = (od.Person.PANICTIME).ToString(),
NO_M_TME = (od.Person.NOMOTIONTIME).ToString(),
OUT_TME = (od.Person.OUT_TIME).ToString(),
TEMP_TME = (od.Person.TEMPEXCEEDTIME).ToString(),
LOW_BAT_TME = (od.Person.LOW_BATTERY_TIME).ToString(),
FOUT_TME = (od.Person.FOUT_TIME).ToString(),
LAST_UPDATE_TIME = (od.Person.LASTUPDATEDTIME).ToString(),
TEMP_VAL = (decimal)(od.Person.TEMP_VALUE),
NO_OF_OUT = (
from o in db.RTLS_FAULT_DTLS
where (o.faultno == (int)Constants.Faults.LowBattery)
where (startOfThisDay <= o.ORC_DATETIME && o.ORC_DATETIME <= todayEndDate)
where (o.PERSON_ID.ToLower() == od.Person.PERSONID.ToLower())
select o.fltname).Count(),
NO_OF_PANIC = (
from o in db.RTLS_FAULT_DTLS
where o.faultno == (int)Constants.Faults.Panic
where (startOfThisDay <= o.ORC_DATETIME && o.ORC_DATETIME <= todayEndDate)
where (o.PERSON_ID.ToLower() == od.Person.PERSONID.ToLower())
select o.fltname).Count(),
NO_OF_IN_ACTIVE = (
from o in db.RTLS_FAULT_DTLS
where o.faultno == (int)Constants.Faults.InActive
where (startOfThisDay <= o.ORC_DATETIME && o.ORC_DATETIME <= todayEndDate)
where (o.PERSON_ID == od.Person.PERSONID)
select o.fltname).Count(),
NO_OF_TEMP = (
from o in db.RTLS_FAULT_DTLS
where (o.faultno == (int)Constants.Faults.HighTemp || o.faultno == (int)Constants.Faults.LowTemp)
where (startOfThisDay <= o.ORC_DATETIME && o.ORC_DATETIME <= todayEndDate)
where (o.PERSON_ID == od.Person.PERSONID)
select o.fltname).Count(),
NO_OF_LBAT = (
from o in db.RTLS_FAULT_DTLS
where o.faultno == (int)Constants.Faults.LowBattery
where (startOfThisDay <= o.ORC_DATETIME && o.ORC_DATETIME <= todayEndDate)
where (o.PERSON_ID == od.Person.PERSONID)
select o.fltname).Count(),
LOCS = fzones.ToList()
}).ToList();
我的getZoneList方法如下所示,在上面的查询中使用。
public int[] getZoneList(decimal[] zoneIdsArray)
{
int[] zoneIds = Array.ConvertAll(zoneIdsArray, x => (int)x);
List<int> list = zoneIds.ToList();
for (int c = 1; c < zoneIdsArray.Count(); c++)
{
if (zoneIdsArray[c] == zoneIdsArray[c - 1])
{
list.Remove((int)zoneIdsArray[c]);
}
}
return list.ToArray();
}
对于我的应用程序,我在visual studio-2015中使用WebApi2编写了一个Web服务,其中Entity框架为ORM,Azure_SQL为后端。我观察到上面的linq查询至少需要25秒到最多1.5分钟才能执行(使用azure portal的查询性能洞察工具来查找它)。 在逐行评论和测试之后,我逐渐了解了
from od in peopleStatus.AsNoTracking().ToList()
这条线花了很多时间(平均55秒)。我无法跳过转换为List以进一步使用。建议我如何优化查询以减少整体周转时间。
答案 0 :(得分:1)
如果我没记错的话,这段代码
NO_OF_OUT = (from o in db.RTLS_FAULT_DTLS
where (o.faultno == (int)Constants.Faults.LowBattery)
where (startOfThisDay <= o.ORC_DATETIME && o.ORC_DATETIME <= todayEndDate)
where (o.PERSON_ID.ToLower() == od.Person.PERSONID.ToLower())
select o.fltname).Count(),
NO_OF_PANIC = (from o in db.RTLS_FAULT_DTLS
where o.faultno == (int)Constants.Faults.Panic
where (startOfThisDay <= o.ORC_DATETIME && o.ORC_DATETIME <= todayEndDate)
where (o.PERSON_ID.ToLower() == od.Person.PERSONID.ToLower())
select o.fltname).Count(),
NO_OF_IN_ACTIVE = (from o in db.RTLS_FAULT_DTLS
where o.faultno == (int)Constants.Faults.InActive
where (startOfThisDay <= o.ORC_DATETIME && o.ORC_DATETIME <= todayEndDate)
where (o.PERSON_ID == od.Person.PERSONID)
select o.fltname).Count(),
NO_OF_TEMP = (from o in db.RTLS_FAULT_DTLS
where (o.faultno == (int)Constants.Faults.HighTemp || o.faultno == (int)Constants.Faults.LowTemp)
where (startOfThisDay <= o.ORC_DATETIME && o.ORC_DATETIME <= todayEndDate)
where (o.PERSON_ID == od.Person.PERSONID)
select o.fltname).Count(),
NO_OF_LBAT = (from o in db.RTLS_FAULT_DTLS
where o.faultno == (int)Constants.Faults.LowBattery
where (startOfThisDay <= o.ORC_DATETIME && o.ORC_DATETIME <= todayEndDate)
where (o.PERSON_ID == od.Person.PERSONID)
select o.fltname).Count(),
基本相同,唯一的区别是你想要计算的错误。您可以尝试使用group by faultno并立即获取所有内容。
编辑: Linq不是我的强项,但也许这会起作用:
from o in db.RTLS_FAULT_DTLS
where (startOfThisDay <= o.ORC_DATETIME && o.ORC_DATETIME <= todayEndDate)
where (o.PERSON_ID == od.Person.PERSONID)
group o by o.faultno
into g
select new
{
faultno = g.Key,
count = g.Count()
};
答案 1 :(得分:0)
最后,通过删除 AsNoTracking()。ToList(),我将查询执行时间从55秒减少到平均4.5秒。
旧查询花了太多时间执行。
var onlineData = from od in peopleStatuc.AsNoTracking().ToList()
我的总周转时间大幅下降的新查询。
var onlineData = from od in peopleStats
我发现在执行子查询时,我不必要地将我的结果转换为列表(在记录增加时将结果转换为列表的时间增加),因此将其删除。