代码之家  ›  专栏  ›  技术社区  ›  Antony

优化Linq to SQL查询,按多个字段分组

  •  0
  • Antony  · 技术社区  · 14 年前

    我的LINQ查询包含以下Group By语句:

    Group p By Key = New With { _
    .Latitude = p.Address.GeoLocations.FirstOrDefault(Function(g) New String() {"ADDRESS", "POINT"}.Contains(g.Granularity)).Latitude, _
    .Longitude = p.Address.GeoLocations.FirstOrDefault(Function(g) New String() {"ADDRESS", "POINT"}.Contains(g.Granularity)).Longitude}
    

    查询有效,但下面是上面的子句生成的SQL

    SELECT [t6].[Latitude]
                FROM (
                    SELECT TOP (1) [t5].[Latitude]
                    FROM [dbo].[GeoLocations] AS [t5]
                    WHERE ([t5].[Granularity] IN (@p0, @p1)) AND ([t5].[AddressId] = [t2].[Addr_AddressId])
                    ) AS [t6]
                ) AS [value], (
                SELECT [t8].[Longitude]
                FROM (
                    SELECT TOP (1) [t7].[Longitude]
                    FROM [dbo].[GeoLocations] AS [t7]
                    WHERE ([t7].[Granularity] IN (@p2, @p3)) AND ([t7].[AddressId] = [t2].[Addr_AddressId])
                    ) AS [t8]
                ) AS [value2]
    

    我不是SQL专家,但在我看来,这是一个相当次优的翻译。这应该是从第一条记录中选择纬度和经度的一个查询。也许SQL Server优化器会处理这个问题。但是有没有一种方法可以推动Linq生成一个更精简的SQL语句?

    我也试过以下的……

    Group p By Key = p.Address.GeoLocations.Where(Function(g) New String() {"ADDRESS", "POINT"}.Contains(g.Granularity)). _
    Select(Function(g) New With {.Latitude = g.Latitude, .Longitude = g.Longitude}).FirstOrDefault
    

    但这产生了一个错误:“按表达式分组只能包含服务器可比较的非常量标量。”

    1 回复  |  直到 14 年前
        1
  •  1
  •   Amy B    14 年前

    很抱歉用C语言回复…

    以下是你的资料,翻译成C:

    List<string> params = new List<string>()
    { "Address", "Point" };
    
    from p in people
    group p by new {
      Latitude = p.Address.GeoLocations
        .FirstOrDefault(g => params.Contains(g.Granularity)).Latitude,
      Longitude = p.Address.GeoLocations
        .FirstOrDefault(g => params.Contains(g.Granularity)).Longitude
    };
    

    这里有一个重写,使用 let 关键字。

    from p in people
    let loc = p.Address.GeoLocations
       .FirstOrDefault(g => params.Contains(g.Granularity))
    group p by new
    {
      Latitude = loc.Latitude,
      Longitude = loc.Longitude
    };