我试图获取已更改的记录,其中车辆点火已更改。这是我的SQL表。
即我想获取记录47890并记录47879。
我已经编写了以下相关的LINQ查询。
var sData = (from log in db.GSMDeviceLogs
where log.Vehicle.VehicleId == vehicleId
where log.IgnitionOn != (from prevLog in db.GSMDeviceLogs
where prevLog.Vehicle.VehicleId == vehicleId
where prevLog.DateTimeOfLog < log.DateTimeOfLog
orderby prevLog.DateTimeOfLog descending
select prevLog.IgnitionOn).FirstOrDefault()
orderby log.DateTimeOfLog ascending
select new { LogId = log.GSMDeviceLogId,
Ignition = log.IgnitionOn,
Date = log.DateTimeOfLog,
Location = log.Location }).ToList();
它提供以下例外:
An exception of type 'System.Data.Entity.Core.EntityCommandExecutionException' occurred in EntityFramework.SqlServer.dll but was not handled in user code
内部异常说:
{"Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding."}
我希望这是因为查询效率非常低并且执行时间太长。我们如何优化LINQ查询?
答案 0 :(得分:0)
没关系,你可以用一个漂亮的sproc或一些神奇的SQL做一些更高效的事情。但是,不管出于何种原因,我们都说你不能。这并不意味着您必须放弃或运行一些SELECT N + 1代码。如果您正确订购了序列(正如您已经在做的那样),您可以使用Linq扫描序列一次,并使用一些智能扩展方法来记住以前的值。在工具箱中使用类似的东西:
static class EnumerableExtensions
{
public static IEnumerable<TR> Pair<T, TR>(this IEnumerable<T> source, Func<T, T, TR> resultor)
{
return PairImpl<T, TR>(source, resultor);
}
static IEnumerable<TR> PairImpl<T, TR>(IEnumerable<T> source, Func<T, T, TR> resultor)
{
var e = source.GetEnumerator();
var a = default(T);
while (e.MoveNext())
{
var b = e.Current;
yield return resultor(a, b);
a = b;
}
}
}
然后你可以写一个这样的表达式:
var logs =
from log in db.GSMDeviceLogs
where log.Vehicle.VehicleId == vehicleId
orderby log.DateTimeOfLog ascending
select log;
var diffs =
from log in logs.Pair((a, b) => new { a, b })
where log.a != null && log.a.IgnitionOn != log.b.IgnitionOn
select log.a;
这会扫描内存中的 所有记录,但只扫描一次,然后以富有表现力的方式完成。如上所述,在数据库级别执行它会更有效,但也许你不能去那里。
MoreLinq项目包含了扩展方法,就像我在这里粗略建议的那样。
答案 1 :(得分:0)
自我加入:
var sData = (from log in db.GSMDeviceLogs
join log2 in db.GSMDeviceLogs on log.GSMDeviceLogId equals log2.GSMDeviceLogId - 1
where log.Vehicle.VehicleId == vehicleId
&& log.IgnitionOn != log2.IgnitionOn
orderby log.DateTimeOfLog ascending
select new { LogId = log.,
Ignition = log.IgnitionOn,
Date = log.DateTimeOfLog,
Location = log.Location }).ToList();