我正在使用EF,Linq,TSQL。我有两张桌子:
Positions:
Id [int]
Location [geography, nullable]
TimestampLocal [datetimeoffset(7)]
VehicleId [int]
Rawdata:
Id [int]
TimestampLocal [datetimeoffset(7)]
Data1 [string]
VehicleId [int]
我需要通过时间戳为特定的VehicleId加入两个表中的信息,时间戳接近但不相同。我使用MoreLinq来获取数据。 现在我将列表中的位置,然后是另一个列表中的Rawdata,然后迭代它们以获取Rawdata样本的位置,然后对该信息执行某些操作(计算nearestPos.Location.Intersects(Polygon).. )。
var posList = entities.Positions.Where(z => (z.VehicleId == SearchedVehicleId && z.Location != null)
&& z.TimestampLocal.Day == SearchedDay && z.TimestampLocal.Month == SearchedMonth && z.TimestampLocal.Year == SearchedYear).AsEnumerable().OrderBy(k => k.TimestampLocal);
var rawdatalist=entities.Rawdata.Where(k => (k.VehicleId == SearchedVehicleId)
&& k.TimestampLocal.Day == SearchedDay && k.TimestampLocal.Month == SearchedMonth && k.TimestampLocal.Year == SearchedYear).OrderBy(k => k.TimestampLocal).ToList();
foreach (Rawdata r in rawdatalist){
var closestPos = posList.MinBy(t => Math.Abs((t.TimestampLocal- r.TimestampLocal).Ticks));
//do something with the location
ComputeRawdataforLocation(closestPos, r);
}
从数据库获取数据(即使使用AsEnumerable(),ToList())也很快。问题是有大约10k的位置和100k的Rawdata值。
我怎样才能加快速度? Linq的另一种方式?也许我可以调用的TSQL程序会加入值?我不知道如何在TSQL中执行此操作。
答案 0 :(得分:0)
从数据库获取数据(即使使用AsEnumerable(),ToList())也很快。
好的,那么你需要优化慢速搜索(MinBy
是O(N)时间复杂度)。
忘了LINQ。您可以利用posList
已排序的事实,这意味着线性搜索可以用更快的O(log(N))二进制搜索替换。
BCL BinarySearch
方法不能用于此类方案。但是从头开始编写方法并不难,比如:
static Positions FindClosest(List<Positions> posList, DateTimeOffset value)
{
int lo = 0, hi = posList.Count - 1;
while (lo <= hi)
{
int pos = lo + (hi - lo) / 2;
var item = posList[pos];
int compare = value.CompareTo(item.TimestampLocal);
if (compare < 0) hi = pos - 1;
else if (compare > 0) lo = pos + 1;
else return item;
}
var next = lo < posList.Count ? posList[lo] : null;
var prev = lo > 0 ? posList[lo - 1] : null;
if (next == null) return prev;
if (prev == null) return next;
return (value - prev.TimestampLocal).Ticks <= (next.TimestampLocal - value).Ticks ? prev : next;
}
然后使用它代替MinBy
:
foreach (Rawdata r in rawdatalist)
{
var closestPos = FindClosest(posList, r.TimestampLocal);
//do something with the location
ComputeRawdataforLocation(closestPos, r);
}