Linq2Entities CompiledQuery для запроса, который использует соединения - PullRequest
3 голосов
/ 28 марта 2012

У меня есть запрос, который работает не очень хорошо, например, сгенерированный код SQL является неоптимальным.

Исходное утверждение выглядело примерно так (упрощенно):

ctx.Table1.Where(t => ...)
          .OrderBy(t => ....)
          .Select(t => new {Table1 = t,
                            SomeProperty = t.Table2.SomeProperty,
                            SomeProperty2 = t.Table2.SomeProperty2,
                            AnotherProperty = t.Table3.AnotherProperty,
                            ...
                            }

Я заглянул в SQL Profiler и обнаружил, что сгенерированный SQL будет присоединяться к одной и той же таблице несколько раз, а выполнение инструкции займет около 1 секунды.

Затем я переписал это утверждение так:

from t in ctx.Table1
join t2 in ctx.Table2 on t.key equals t2.key into lt2
from t2 in lt2.DefaultIfEmpty()
join t3 in ctx.Table3 on t.key equals t3.key into lt3
from t3 in lt3.DefaultIfEmpty()
where t ...
orderby t...
select new {Table1 = t, .... }

Это породило гораздо более приятное утверждение, что при извлечении из SQL-профилировщика и выполнении в Management studio он вдвое быстрее, чем оператор, сгенерированный кодом в предыдущем примере.

Однако при выполнении кода из второго примера время, затраченное на EF для генерации выражения, намного превосходит время, полученное при оптимизации запроса.

Итак, как мне написать оператор номер два как CompiledQuery. Я в основном не знаю, как вернуть анонимный тип из CompiledQuery.

Ответы [ 2 ]

0 голосов
/ 29 марта 2012

Вы можете использовать Tuple класс, если ваш возвращаемый объект будет иметь 8 или менее свойств. Если у вас больше свойств и вы не хотите объявлять класс для этих свойств, вы можете использовать dynamic в качестве возвращаемого типа.

0 голосов
/ 28 марта 2012

Обходной путь, который я нашел для использования CompiledQueries:

  1. Добавьте частный метод InitQueryX () перед каждым методом QueryX (), который использует LINQ to Entity.
  2. Используйте атрибуты и отражениевызовите все методы InitQueryX () из метода Init ().
  3. Вызовите метод Init () один раз при запуске приложения.

Это вызывает компиляцию запросов при запуске, но позволяет писатьЗапросы выполняются более гибко, чем в CompiledQueries.

InitQueryX () должен использовать несколько фиктивных входных данных, чтобы он охватывал все пути в методе QueryX () (что-то вроде покрытия кода модульных тестов).

Когда это возможно, входные данные InitQueryX () должны быть ложными, в результате чего в базе данных будет 0 строк, поэтому запуск метода Init () займет меньше времени.

...