按大致时间戳加入2个表

时间:2016-04-15 21:27:26

标签: c# entity-framework linq tsql join

我正在使用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中执行此操作。

1 个答案:

答案 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);
}