2016-04-15 9 views
1

私はEF、Linq、TSQLを使用しています。2つのテーブルをおおよそのタイムスタンプで結合する

Positions: 
Id [int] 
Location [geography, nullable] 
TimestampLocal [datetimeoffset(7)] 
VehicleId [int] 

Rawdata: 
Id [int] 
TimestampLocal [datetimeoffset(7)] 
Data1 [string] 
VehicleId [int] 

私は近いが同一ではないタイムスタンプで、特定のVehicleIdのためのタイムスタンプで2つのテーブルの情報を結合する必要があります。私は2つのテーブルを持っています。私は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()を使用しても)DBからデータを取得するのは高速です。問題は、aprox 10kの位置と100kのRawdata値があることです。

どのように高速化できますか? Linqの別の方法ですか?おそらく、私が値を結合することができるTSQLプロシージャですか?私はTSQLでこれを行う方法を知りません。

答えて

0

(AsEnumerable()、ToList()を使用しても)DBからデータを取得するのは高速です。

[OK]をクリックすると、低速検索(MinByはO(N)時間の複雑さです)を最適化する必要があります。

LINQについては忘れてください。 posListがソートされているという事実を利用することができます。つまり、線形検索は、はるかに高速なO(log(N))バイナリ検索に置き換えることができます。

このようなシナリオでは、BCL BinarySearchメソッドは使用できません。 MinByの代わりに使用、その後

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; 
} 

と::しかし、それはこのように、ゼロからメソッドを書くことは難しいことではありません

foreach (Rawdata r in rawdatalist) 
{ 
    var closestPos = FindClosest(posList, r.TimestampLocal); 
    //do something with the location 
    ComputeRawdataforLocation(closestPos, r); 
} 
+0

ありがとうございます! posListの最後に.ToList()を適用して、動作させるだけでした。これにより、平均10%の時間が短縮されました。しかし、私は自分のコードを見て、私は(AsEnumerableを持っていた)ローカルのIISデータをDBクエリデータと混合していたので、 (DBサーバ上に保持されている)。これはCPUを5%にしました。 IIS上のすべてのデータを(AsEnumberableで)引っ張った後、CPUは40%になり、計算時間はコードによって大幅に減少しました。 – user3546827

+0

私は 'posList'がリストではないことを忘れてしまいました。しかし、私は 'var posList = entities .... ToList();'の最後に 'ToList'を呼び出すことをお勧めします。そしてそれを答えとして使用してください(内部ループ内の' ToList'呼び出しではありません)。それは実際に10%以上を与えるはずです。もし10Kのポジションを持っていれば、バイナリ検索は〜13の比較を使いますが、元のものは約13です。 5-10Kの比較では、新しい方法は時間がかかるはずです。 –

関連する問題