1

少し前に、SQL Serverに質問しました:group byで集計関数を使用してデータの整合性を維持するにはどうすればよいですか?私はそこで素晴らしい答えを得ましたが、今度は問題が再び発生しました。今回は、プレーンSQLではなくLinqtoSQLを使用しました。

バックストーリー:gpsデータでいっぱいのテーブルがあります。これは次のようになります。

GPS_id、user_id、緯度、経度、server_time、device_time

次のlinqクエリを使用して、特定のユーザーセットの最新のgpsレコードを取得しました。

var query =
    from gps in db.gps_data
    where (from u in db.users
        select u.user_id).Contains(gps.user_id)
    group gps by gps.user_id into groupedGPS
    select groupedGPS;

次に、そのようにループしましたが、「最新のレコード」を適切に取得するには、最初に注文する必要がありました。

foreach (var gpsItem in query) {
    var ordered = gpsItem.OrderByDescending(g => g.device_time);
    list.Add(ordered.First());
}

これで必要なものが得られましたが、いつでも100人以上のユーザーが500人以上のgpsレコードを持っているので(そしてすべてのユーザーがこの方法でアクセスされていた)、このコードは10秒以上かかっていました。

その後、次のように変更しました

var query =
    from gps in db.gps_data
    where (from u in db.users
        select u.user_id).Contains(gps.user_id)
    group gps by gps.user_id into groupedGPS
    select new 
    {
        GPS_id = groupedGPS.Max(x => x.GPS_id),
        user_id = groupedGPS.Max(x => x.user_id),
        latitude = groupedGPS.Max(x => x.latitude),
        longitude = groupedGPS.Max(x => x.longitude),
        server_time = groupedGPS.Max(x => x.server_time),
        device_time = groupedGPS.Max(x => x.device_time) 
    };

私の理解では、不要なデータがすべて実際にメモリにロードされることはないため、このクエリはより高速に見えました。ただし、数か月前の最初の質問のように、この方法でデータの整合性が失われました。グループ内のすべてのフィールドの最大値だけで、最新のレコードが表示されるという保証はありません。max()これはほとんどのフィールドに影響を与えませんが、緯度と経度は、最新のものではなく、グループ化で見つかったレコードにすぎないため、ほとんどの場合正しくありません。

この問題を回避するにはどうすればよいですか?正しいデータを取得する最初のソリューションがあることはわかっていますが、時間がかかりすぎます。

助けてくれてありがとう!

4

2 に答える 2

1

私があなたの質問(ユーザーIDごとの最新のレコード)を理解している限り、これはあなたが探していることをするように思えます。

var q =
    from gps in db.gps_data
    where (from gps2 in db.gps_data
           group gps2 by gps2.user_id
           into g
           select new {a = g.Key, b = g.Max(f => f.server_time)})
           .Contains(new {a = gps.user_id, b = gps.server_time})
    select gps;

ユーザーに対して同時に複数の読み取り値がある場合は、重複する可能性がありますが、そうではないと思います。

于 2012-09-18T18:26:57.480 に答える
0

以下は機能するはずですが、複数のサブ選択を実行するため、パフォーマンスをチェックし、インラインFirstOrDefaultがLINQプロバイダーで機能することを確認する必要があります。

var query =
    from u in db.users
    select new
    {
        u.user_id,
        latestGPS = (db.gps_data
                    where g.user_id == u.user_id
                    orderby g.server_time descending
                    select g).FirstOrDefault()
    };
于 2012-09-18T18:56:45.563 に答える