2015-02-08 2 views
4

Я использую EF6, и я хотел бы получить записи в таблице, которые находятся в группе идентификаторов.Это лучше или нет, чем это содержит?

В моем тесте, например, я использую 4 идентификатора.

Я пробую два варианта, первый с любым.

dbContext.MyTable 
.Where(x => myIDS.Any(y=> y == x.MyID)); 

И T-SQL, который генерирует этот LINQ exrepsion является:

SELECT 
    * 
    FROM [dbo].[MiTabla] AS [Extent1] 
    WHERE EXISTS (SELECT 
     1 AS [C1] 
     FROM (SELECT 
      [UnionAll2].[C1] AS [C1] 
      FROM (SELECT 
       [UnionAll1].[C1] AS [C1] 
       FROM (SELECT 
        cast(130 as bigint) AS [C1] 
        FROM (SELECT 1 AS X) AS [SingleRowTable1] 
       UNION ALL 
        SELECT 
        cast(139 as bigint) AS [C1] 
        FROM (SELECT 1 AS X) AS [SingleRowTable2]) AS [UnionAll1] 
      UNION ALL 
       SELECT 
       cast(140 as bigint) AS [C1] 
       FROM (SELECT 1 AS X) AS [SingleRowTable3]) AS [UnionAll2] 
     UNION ALL 
      SELECT 
      cast(141 as bigint) AS [C1] 
      FROM (SELECT 1 AS X) AS [SingleRowTable4]) AS [UnionAll3] 
     WHERE [UnionAll3].[C1] = [Extent1].[MiID] 
    ) 

Как видно, T-SQL является "где существует", которые используют много подзапросы и объединения.

Второй вариант с содержит.

dbContext.MyTable 
.Where(x => myIDS.Contains(x.MiID)); 

И T-SQL:

SELECT 
    * 
    FROM [dbo].[MiTabla] AS [Extent1] 
    WHERE [Extent1].[MiID] IN (cast(130 as bigint), cast(139 as bigint), cast(140 as bigint), cast(141 as bigint)) 

содержит переводится в "где в", но запрос гораздо менее сложным.

Я читал, что любой из них используется быстрее, поэтому я сомневаюсь, что любой из них, хотя он сложнее на первый взгляд, быстрее или нет.

Большое спасибо.

EDIT: У меня есть тест (я не знаю, если это лучший способ проверить это).

System.Diagnostics.Stopwatch miswContains = new System.Diagnostics.Stopwatch(); 
         miswContains.Start(); 
         for (int i = 0; i < 100; i++) 
         { 
          IQueryable<MyTable> iq = dbContext.MyTable 
          .Where(x => myIDS.Contains(x.MyID)); 

          iq.ToArrayAsync(); 
         } 
         miswContains.Stop(); 



         System.Diagnostics.Stopwatch miswAny = new System.Diagnostics.Stopwatch(); 
         miswAny.Start(); 
         for (int i = 0; i < 20; i++) 
         { 
          IQueryable<MyTable> iq = dbContext.Mytable 
          .Where(x => myIDS.Any(y => y == x.MyID)); 

          iq.ToArrayAsync(); 
         } 
         miswAny.Stop(); 

результат: miswAny около 850 мс, а miswContains - около 4251 мс.

Итак, второй вариант с контациями медленнее.

+0

'Entity Framework' сгенерировал код с помощью' select * '? Являются ли идентификаторы типа длинными? Откуда вы знаете, если результат не кэширован, попытались ли вы поменять порядок запросов? – Ofiris

ответ

2

Ваш второй вариант является самым быстрым решением я могу думать (по крайней мере, для не очень больших массивов ид) при условии, ваш MiTabla.MiID находится в индекс.

Если вы хотите узнать больше о in статья: Is SQL IN bad for performance?.

+0

У меня есть исходное сообщение, чтобы добавить тест. Но я не знаю, является ли это лучшим способом проверить эти случаи. –

+1

Нет, это не так, потому что вы не принимаете во внимание некоторые внешние факторы, такие как кеш SQL или чистую задержку, хотя это может дать вам приблизительную оценку. Во всяком случае, вы повторяете 20 раз, чтобы выполнить второй тест, а 100 - первый (и результаты показывают, что он в 5 раз быстрее, возможно, из-за этого). Кроме того, вы должны, вероятно, использовать команду 'iq.ToArrayAsync()' – Joanvo

+0

спасибо, я не понимаю, что я использую метод async. –

1

Если вы знаете идентификатор, метод затем с помощью Linq2SQL Count() будет создавать гораздо чище и более быстрый код SQL (чем как любой и содержит):

dbContext.MyTable 
.Where(x => myIDS.Count(y=> y == x.MyID) > 0); 

Сгенерированный SQL для подсчета следует искать что-то как это:

DECLARE @p0 Decimal(9,0) = 12345 
SELECT COUNT(*) AS [value] 
FROM [ids] AS [t0] 
WHERE [t0].[id] = @p0 
+0

Я знаю идентификаторы в этом случае. Но когда у меня много идентификаторов, как это будет запрос? –

+1

Вы проверяете количество совпадений - если счет положителен (по крайней мере, 1, если идентификатор не уникален), тогда список идентификаторов содержит указанный идентификатор. – pasty

1

Вы можете сказать по форме запросов, которые Any не масштабируется на всех. Не требуется много элементов в myIDS (вероятно, ~ 50), чтобы получить исключение SQL, превышающее максимальный уровень вложенности.

Contains намного лучше в этом отношении. Он может обрабатывать несколько тысяч элементов до того, как его производительность сильно пострадает.

Итак, я бы выбрал масштабируемое решение, хотя Any может быть быстрее с небольшими номерами.Можно сделать Contains даже better scalable.

Я прочитал, что любое использование, чтобы быть быстрее,

В LINQ к объектам, которые в целом верно, потому что перечисление останавливается на первом ударе. Но с LINQ против SQL-сервера, сгенерированный SQL - это то, что считается.

Смежные вопросы