Альтернатива для Where Id IN (x, y, z), сгенерированного оператором linq - PullRequest
1 голос
/ 25 августа 2011

Когда создается запрос linq как:

var ids = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var q = from r in context.Table
        where ids.Contains(r.Id)
        select r;

для использования с EF генерирует T-SQL, аналогичный

SELECT ... FROM Table
    WHERE Id IN ( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 )

В общем, это то, чего я ожидаю, хотя, похоже, он портит «компиляцию плана запроса» в том смысле, что каждый запрос различен и, следовательно, должен быть скомпилирован перед выполнением.

Поскольку EF в противном случае очень хорошо использует переменные ((@ p_ linq _), чтобы избежать этого, он (по умолчанию) не делает этого для запросов такого рода.

Можно ли вообще этого избежать?

Запоминаются параметры с табличным значением, но это пока не поддерживается.

Кстати: в реальной жизни запросы намного сложнее, а количество элементов в списке идентификаторов намного больше, но все же необходимо отфильтровать данные. Мы не хотим фильтровать «клиента».

1 Ответ

0 голосов
/ 25 августа 2011

Я реализовал это один раз, изменив TSQL, сгенерированный EF, для выдачи строкового параметра xml, который оценивался как табличный параметр в самом запросе.

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

В конечном счете, мы в конечном итоге переключили реализацию на подход с подпиской, имея собственный метод Contains, который был отображен как определенная моделью функция (http://blogs.msdn.com/b/efdesign/archive/2009/01/07/model-defined-functions.aspx). Таким образом, использование было похоже на

    var ids = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    var q = from r in context.Table
    where CriteriaHelpers.Contains(ids, r.Id)
    select r;

и это сгенерировало что-то вроде следующего sql (что позволило избежать перекомпиляции плана запроса каждый раз).

SELECT ... FROM Table
WHERE Id IN (SELECT Entity.ID.value('.', 'Id') AS ID FROM @parameterName.nodes('/items/i') AS Entity(ID))

Этот подход также имеет дополнительное преимущество, позволяя обойти ограничение 2100 параметров ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...