EF 6 Parameter Sniffing

前端 未结 5 2036
感动是毒
感动是毒 2020-12-01 08:33

I have a dynamic query that is just too large to put here. Safe to say that in it\'s current form it utilizes a CLR procedure to dynamically build joins based upon the numb

5条回答
  •  遥遥无期
    2020-12-01 09:14

    I like VahidN's solution, do up vote him, but I want more control of when it happens. It turns out that DB Interceptors are very global, and I only wanted this to happen on specific contexts in specific scenarios.

    Here we are setting the ground work to also support adding other query hints, that could be turned on and off as desired.

    Since I often expose the method for passing a connection string, I also included support for that.

    Below would give your context a flag to enable/disable the hint programatically, by extending the partial class EF generates. We also threw the small piece of reused code in the Interceptor into its own method.

    Small Interface

    public interface IQueryHintable
    {
        bool HintWithRecompile { get; set; }
    }
    

    DB Command Interceptor

    public class OptionHintDbCommandInterceptor : IDbCommandInterceptor
    {
        public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext)
        {
            AddHints(command, interceptionContext);
        }
    
        public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext interceptionContext)
        {
        }
    
        public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext interceptionContext)
        {
        }
    
        public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext)
        {
            AddHints(command, interceptionContext);
        }
    
        public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext interceptionContext)
        {
        }
    
        public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext)
        {
            AddHints(command, interceptionContext);
        }
    
        private static void AddHints(DbCommand command, DbCommandInterceptionContext interceptionContext)
        {
            var context = interceptionContext.DbContexts.FirstOrDefault();
            if (context is IQueryHintable)
            {
                var hints = (IQueryHintable)context;
    
                if (hints.HintWithRecompile)
                {
                    addRecompileQueryHint(command);
                }
            }
        }
    
        private static void addRecompileQueryHint(IDbCommand command)
        {
            if (command.CommandType != CommandType.Text || !(command is SqlCommand))
                return;
    
            if (command.CommandText.StartsWith("select", StringComparison.OrdinalIgnoreCase) && !command.CommandText.Contains("option(recompile)"))
            {
                command.CommandText = command.CommandText + " option(recompile)";
            }
        }
    }
    
    
    

    Extending Entity Context to Add IQueryHintable

    public partial class SomeEntities : DbContext, IQueryHintable
    {
        public bool HintWithRecompile { get; set; }
    
        public SomeEntities (string connectionString, bool hintWithRecompile) : base(connectionString)
        {
            HintWithRecompile = hintWithRecompile;
        }
    
        public SomeEntities (bool hintWithRecompile) : base()
        {
            HintWithRecompile = hintWithRecompile;
        }
    
        public SomeEntities (string connectionString) : base(connectionString)
        {
        }
    
    }
    

    Register DB Command Interceptor (global.asax)

        DbInterception.Add(new OptionHintDbCommandInterceptor());
    

    Enable context wide

        using(var db = new SomeEntities(hintWithRecompile: true) )
        {
        }
    

    Turn On or Off

        db.HintWithRecompile = true;
        // Do Something
        db.HintWithRecompile = false;
    

    I called this HintWithRecompile, because you might also want to implement a HintOptimizeForUnknown , or other query hints.

    提交回复
    热议问题