Добавление подсказки при вызове функции с табличными значениями
Я вызываю табличную функцию из структуры сущностей и должен иметь возможность добавить 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;
Я видел этот вопрос:
- Может ли кто-нибудь понять, почему я продолжаю получать эту ошибку, проверяя бета-версию EF 5
- Как установить значение по умолчанию для POCO в EF CF?
- Как передать параметры методу DbContext.Database.ExecuteSqlCommand?
- Установите десятичное значение (16, 3) для столбца в первом подходе кода в EF4.3
- Первый код - сначала модель / firebase database
Как я могу контролировать snuffing параметров и / или подсказки в структуре сущности?
Но он старый, и принятое решение действительно не дает достаточной информации о том, как реально реализовать предлагаемое решение (использовать руководства по планам) с инфраструктурой сущности. Если это единственное решение, как вы все равно получаете структуру сущностей для использования руководства по планированию?
- EF Code First "Недопустимое имя столбца« Дискриминатор », но без наследования
- дизайн схемы базы данных streamов сообщений
- SqlException из Entity Framework - новая транзакция не допускается, поскольку в сеансе есть другие streamи
- Отображение представлений базы данных в EF 5.0 Code First w / Migrations
- Платформа Entity Framework и пул соединений
- Организационно, где я должен ставить общие запросы при первом использовании кода Entity Framework?
- как обновить объект в Entity Framework 4 .NET
- EF 4.1 загрузка фильтрованных дочерних коллекций, не работающих для многих-ко-многим
Я натолкнулся на это:
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;