Производительность EF4 с использованием IN вместо JOIN - PullRequest
2 голосов
/ 10 июня 2011

Есть ли какие-либо проблемы с производительностью, которые необходимо учитывать при использовании этого оператора SQL, сгенерированного EF

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 числом объединений, которое увеличивается с числом позволенныхPois:

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]

Любая идея о том, как улучшить эту операцию, или я должен придерживаться моего фактического решения, используя отдельный запрос для allowPois?

1 Ответ

1 голос
/ 06 августа 2011

Вы действительно не должны использовать синтаксис объединения в запросе LINQ.Часть меня хотела бы, чтобы они не включали оператор соединения в язык C # для LINQ, потому что это просто приводит к путанице и имеет тенденцию генерировать плохой SQL, подобный этому.Причина в том, что вы почти всегда присоединяетесь к SQL, когда хотите сделать предложение where или включить эту таблицу в свои результаты.LINQ уже имеет отличную поддержку для этого, но вы просто должны думать о LINQ, а не о SQL.В вашей модели данных LINQ должны быть определены отношения, поэтому вам не нужно переопределять их через объединения.Не полностью применимо здесь, так как вы сначала используете sproc, но применяются те же принципы.Ваш первый запрос LINQ в 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;
            }
...