【问题标题】:Linq to SQL data integrity with groupingLinq to SQL 数据完整性与分组
【发布时间】:2012-09-18 18:03:03
【问题描述】:

前段时间我问了SQL Server: How do I maintain data integrity using aggregate functions with group by?这个问题,我在那里得到了很好的答案,但现在问题又出现了,这次是Linq to SQL,而不是普通的SQL。

背景故事:我有一个完整的 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() 记录,而不是最近的记录。

如何解决这个问题?我意识到我有第一个解决方案来检索我正确的数据,但是花费的时间太长了。

感谢您的帮助!

【问题讨论】:

    标签: c# sql linq-to-sql query-optimization


    【解决方案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;
    

    如果一个用户同时有多个读数,它可能会给你重复,我假设他们不是。

    【讨论】:

    • 编辑:没关系 - 看起来它工作正常。让我再玩一会儿……
    • 而且效果很好 - 平均 440 毫秒而不是 10 秒。非常感谢!
    【解决方案2】:

    以下应该可以工作,但会执行多个子选择,因此您需要检查您的性能并确保内联 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()
        };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-19
      • 2015-05-29
      • 2012-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多