Добавление подсказки при вызове функции с табличными значениями

Я вызываю табличную функцию из структуры сущностей и должен иметь возможность добавить option (recompile) к ней, потому что план выполнения, который он выбирает, не является оптимальным. Выполнение запроса в SQL Server Management Studio выглядело бы примерно так:

 select * from dbo.fDE_myquery(0, 0, 3309, '7/1/2013', '7/1/2014', 0, 0) option (recompile) 

По EF, нет никакого способа добавить этот намек, AFAIK. Часть EF выглядит примерно так:

 var query = from f in ctx.fDE_myQuery(aBool, anotherBool, StartDate, EndDate, someInt, moreBool) select f; 

Я видел этот вопрос:

Как я могу контролировать snuffing параметров и / или подсказки в структуре сущности?

Но он старый, и принятое решение действительно не дает достаточной информации о том, как реально реализовать предлагаемое решение (использовать руководства по планам) с инфраструктурой сущности. Если это единственное решение, как вы все равно получаете структуру сущностей для использования руководства по планированию?

Я натолкнулся на это:

https://entityframework.codeplex.com/wikipage?title=Interception

И, похоже, вы можете сделать что-то вроде этого:

 public class HintInterceptor : DbCommandInterceptor { public override void ReaderExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext interceptionContext) { command.CommandText += " option (recompile)"; base.ReaderExecuting(command, interceptionContext); } } 

И зарегистрируйте его так (я сделал это в Application_Start из global.asax.cs ):

 DbInterception.Add(new HintInterceptor()); 

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

Не совсем кажется самым элегантным или мелкозернистым решением.

Изменить : из interceptorContext вы можете получить DbContexts , поэтому я определил интерфейс, который выглядит так:

 public interface IQueryHintContext { string QueryHint { get; set; } bool ApplyHint { get; set; } } 

А затем создал class, который происходит из моего исходного DbContext (сгенерированного EF) и реализует вышеуказанный интерфейс. Затем я изменил свой перехватчик, чтобы выглядеть так:

 public class HintInterceptor : DbCommandInterceptor { public override void ReaderExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext interceptionContext) { if (interceptionContext.DbContexts.Any(db => db is Dal.IQueryHintContext)) { var ctx = interceptionContext.DbContexts.First(db => db is Dal.IQueryHintContext) as Dal.IQueryHintContext; if (ctx.ApplyHint) { command.CommandText += string.Format(" option ({0})", ctx.QueryHint); } } base.ReaderExecuting(command, interceptionContext); } } 

Теперь, чтобы использовать его, я создаю контекст с использованием моего производного classа вместо оригинала, QueryHint тем, что я хочу ( recompile в этом случае), и установите ApplyHint прямо до того, как я ApplyHint команду и ApplyHint ее обратно к false.

Чтобы сделать это все более самодостаточным, я в конечном итоге определил такой интерфейс:

 public interface IQueryHintContext { string QueryHint { get; set; } bool ApplyHint { get; set; } } 

И расширил мой db-контекст, как это (вы могли бы, конечно, просто использовать частичный class для расширения classа, сгенерированного EF):

 public class MyEntities_Ext : MyEntities, IQueryHintContext { public string QueryHint { get; set; } public bool ApplyHint { get; set; } } 

И затем, чтобы сделать включение, отключение части немного легче обрабатывать, я определил это:

 public class HintScope : IDisposable { public IQueryHintContext Context { get; private set; } public void Dispose() { Context.ApplyHint = false; } public HintScope(IQueryHintContext context, string hint) { Context = context; Context.ApplyHint = true; Context.QueryHint = hint; } } 

Теперь, чтобы использовать его, я могу сделать именно это:

 using (var ctx = new MyEntities_Ext()) { // any code that didn't need the query hint // .... // Now we want the query hint using (var qh = new HintScope(ctx, "recompile")) { // query that needs the recompile hint } // back to non-hint code } 

Возможно, это немного переборчиво и может быть развито дальше (например, используя перечисление для доступных подсказок вместо строки – или подclassифицировать подсказку запроса recompile поэтому вам не нужно указывать recompile строк каждый раз и подвергать риску опечатку), но он решил мою непосредственную проблему.

Существуют ли другие вызывающие пользователи fDE_myquery вне вашего конкретного использования? И как часто это называется? Проблема не в том, что ваш SELECT * FROM dbo.fDE_myquery(); получает fDE_myquery план, это то, что один или несколько запросов внутри fDE_myquery получают fDE_myquery план. Следовательно, вы можете просто добавить OPTION(RECOMPILE) к одному или нескольким запросам внутри этого TVF.

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

Но если есть несколько других вызывающих абонентов этого TVF, которые не испытывают проблемы, то размещение RECOMPILE в TVF может быть не лучшим способом. Хотя в этом случае вы можете создать оболочку TVF, которая инкапсулирует SELECT * FROM dbo.fDE_myquery() OPTION (RECOMPILE); , Это было бы более гибким решением :). Это должно было бы быть Multistatment TVF вместо типично лучшего Inline TVF, как я только что пробовал, и Inline TVF, похоже, не ценит предложение OPTION , но Multistatement TVF отлично справляется с этим.

РЕДАКТИРОВАТЬ:
Или, если вы хотите обработать это чисто в EF, вы можете просто отправить запрос перекомпиляции с помощью одной строки кода:

 ctx.context.ExecuteStoreCommand("EXEC sp_recompile 'dbo.fDE_myquery';"); 

И затем сделайте свое:

 var query = from f in ctx.fDE_myQuery(aBool, anotherBool, StartDate, EndDate, someInt, moreBool) select f; 
  • Entity Framework слишком медленная. Какие у меня варианты?
  • Метод DbSet.Find смехотворно медленный по сравнению с .SingleOrDefault для ID
  • Должны ли службы всегда возвращать DTO или они могут также возвращать модели домена?
  • Entity Framework 6 Сначала код Значение по умолчанию
  • Строка соединения SQL Server Express для Entity Framework Code First
  • Как сопоставить наследование типа таблицы на тип (TPT) в дизайнере Entity?
  • Код структуры Entity Framework Сначала используйте Guid как идентификатор с другой колонкой Identity
  • Entity Framework: запрос дочерних объектов
  • Зависимость впрыска в единицу работы с использованием репозиториев
  • Улучшать имена свойств навигации при обратном проектировании базы данных
  • От многих до многих сопоставление с дополнительными полями в Fluent API
  • Interesting Posts

    Как объединить списки в список кортежей?

    Функциональное программирование и нефункциональное программирование

    Найти элементы в одном столбце Excel, которые не находятся в другом столбце, и поместить их в новый столбец

    Как измерить прирост производительности при дефрагментации?

    Как устранить недостающие DLL и поврежденные системные файлы после обновления Windows-7?

    Тип аксессуара UITableViewCell, проверенный на доступ и установка других непроверенных

    Как файл .bat может быть «преобразован» в .exe без сторонних инструментов?

    Где установить значение параметра по умолчанию на C ++?

    В чем разница между маской подсети и сетевой маской?

    Переименовать значки сеансов удаленных рабочих столов на физический рабочий стол

    C / C ++ int vs int * (указатели и обозначения массива). В чем разница?

    Вопрос для интервью – поиск в отсортированном массиве X для индекса i такой, что X = i

    Почему Excel не автоматически обновляет мои уравнения?

    Диалоговое окно «Открыть файл с» при запуске?

    socket.io и сеанс?

    Давайте будем гением компьютера.