使用IN代替JOIN的EF4性能

时间:2011-06-10 02:51:15

标签: sql-server performance entity-framework-4 linq-to-entities

使用EF

生成的sql语句是否存在任何性能问题

C#代码:

 public IQueryable<Lugar> NearestPOI(double lat, double lng, int> distance)
            {
                System.Data.Objects.ObjectResult<Int32?> AllowedPois = dbContext.SP_NearestPOI(lat, lng, 100000);


                IQueryable<Lugar> POI = from c in dbContext.Lugars
                          where AllowedPois.Contains(c.id)
                          select c;

                return POI;
            }

EF4生成的查询:

SELECT 
[Extent1].[id] AS [id], 
[Extent1].[empresaId] AS [empresaId], 
[Extent1].[usuarioId] AS [usuarioId], 
[Extent1].[name] AS [name], 
[Extent1].[description] AS [description], 
[Extent1].[lat] AS [lat], 
[Extent1].[lng] AS [lng],
[Extent1].[logoThumbnail] AS [logoThumbnail], 
[Extent1].[imageType] AS [imageType]
FROM [dbo].[Lugares] AS [Extent1]
WHERE [Extent1].[id] IN (1,2,3,4,5,6,7)

我担心的是将AllowedPois查询作为一个单独的查询,在纯SQL语法上使用常规方法,如下所示:

SELECT * from dbo.Lugares  L join dbo.NearestPOI(9.105306627167566,-79.38148587942118,100000) NL
on L.id = NL.id

由于我在这个项目中使用EF4,我想坚持使用它,并且不要使用字符串连接来查询。我尝试使用这种方法生成更引人注目的查询:

var POI = from c in dbContext.Lugars
          join i in dbContext.SP_NearestPOI(lat, lng, 100000) on c.id  equals i.Value
          select c;

但是它给出了一个非常混乱的查询,其中包含N个联合,它们以allowedPois的数量递增:

SELECT 
[Extent1].[id] AS [id], 
[Extent1].[empresaId] AS [empresaId], 
[Extent1].[usuarioId] AS [usuarioId], 
[Extent1].[name] AS [name], 
[Extent1].[description] AS [description], 
[Extent1].[lat] AS [lat], 
[Extent1].[lng] AS [lng], 
[Extent1].[logoThumbnail] AS [logoThumbnail], 
[Extent1].[imageType] AS [imageType]
FROM  [dbo].[Lugares] AS [Extent1]
INNER JOIN  (SELECT 
    [UnionAll5].[C1] AS [C1]
    FROM  (SELECT 
        [UnionAll4].[C1] AS [C1]
        FROM  (SELECT 
            [UnionAll3].[C1] AS [C1]
            FROM  (SELECT 
                [UnionAll2].[C1] AS [C1]
                FROM  (SELECT 
                    [UnionAll1].[C1] AS [C1]
                    FROM  (SELECT 
                        1 AS [C1]
                        FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
                    UNION ALL
                        SELECT 
                        2 AS [C1]
                        FROM  ( SELECT 1 AS X ) AS [SingleRowTable2]) AS [UnionAll1]
                UNION ALL
                    SELECT 
                    3 AS [C1]
                    FROM  ( SELECT 1 AS X ) AS [SingleRowTable3]) AS [UnionAll2]
            UNION ALL
                SELECT 
                4 AS [C1]
                FROM  ( SELECT 1 AS X ) AS [SingleRowTable4]) AS [UnionAll3]
        UNION ALL
            SELECT 
            5 AS [C1]
            FROM  ( SELECT 1 AS X ) AS [SingleRowTable5]) AS [UnionAll4]
    UNION ALL
        SELECT 
        6 AS [C1]
        FROM  ( SELECT 1 AS X ) AS [SingleRowTable6]) AS [UnionAll5]
UNION ALL
    SELECT 
    7 AS [C1]
    FROM  ( SELECT 1 AS X ) AS [SingleRowTable7]) AS [UnionAll6] ON [Extent1].[id] = [UnionAll6].[C1]

有关如何改进此操作的任何想法,还是应该使用对allowedPois的单独查询来坚持我的实际解决方案?

1 个答案:

答案 0 :(得分:1)

你真的不应该在LINQ查询中使用连接语法。我的一部分希望他们没有在LINQ的C#语言中包含join运算符,因为它只会导致混乱,并且往往会产生这样的错误SQL。原因在于,当您想要执行where子句或在结果中包含该表时,您几乎总是加入SQL。 LINQ已经为此提供了很好的支持,但你只需要考虑LINQ方式而不是SQL方式。您的LINQ数据模型应该定义关系,因此您不需要通过连接重新定义它们。这里并不完全适用,因为您首先使用的是sproc,但适用相同的原则。您在C#中的第一个LINQ查询实际上是有效的方法。

所以,如果我不清楚的话。这是正确的代码。

public IQueryable<Lugar> NearestPOI(double lat, double lng, int> distance)
            {
                System.Data.Objects.ObjectResult<Int32?> AllowedPois = dbContext.SP_NearestPOI(lat, lng, 100000);


                IQueryable<Lugar> POI = from c in dbContext.Lugars
                          where AllowedPois.Contains(c.id)
                          select c;

                return POI;
            }