我有一个使用 EF Core 3.1 在 .NET Framework 上运行的 webjob 项目。
Webjob 处理来自 Azure 服务总线的消息并将其保存到 Azure SQL 数据库中。
我遇到的问题是 Azure SQL 数据库为 EF Core 生成的查询生成非常糟糕的查询计划。使用生成的查询计划,执行时间为 1-2 分钟。但是当我使用OPTION (OPTIMIZE FOR UNKNOWN)
执行时间下降至 0.01 - 0.02 分钟。
所以现在我想实现OPTION (OPTIMIZE FOR UNKNOWN)
在 EF Core 中。我发现他们添加了一个DbCommandInterceptor
在 EF Core 3.1 中,您可以在哪里将内容附加到查询中:MSDOCS https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.x/#interception-of-database-operations
public class HintCommandInterceptor : DbCommandInterceptor
{
public override InterceptionResult<DbDataReader> ReaderExecuting(
DbCommand command,
CommandEventData eventData,
InterceptionResult<DbDataReader> result)
{
// Manipulate the command text, etc. here...
command.CommandText += " OPTION (OPTIMIZE FOR UNKNOWN)";
return result;
}
}
但似乎这个拦截器将在每个查询上运行,而我只希望它用于特定查询。
我可以为此拦截器实现一个单独的 DbContext,但这似乎不是一个可靠的解决方案。
有谁知道我如何以正确的方式实现这一点?
我创建了一个界面:
public interface IInterceptable
{
bool EnableCommandInterceptors { get; set; }
}
并在我的上下文类中实现它:
public bool EnableCommandInterceptors { get; set; }
在拦截器中我有:
public override InterceptionResult<DbDataReader> ReaderExecuting(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result)
{
if(command.CommandText.StartsWith("SELECT")
&& eventData.Context is IInterceptable intercepatable
&& intercepatable.EnableCommandInterceptors)
{
command.CommandText += " OPTION (OPTIMIZE FOR UNKNOWN)";
}
return result;
}
这允许打开和关闭此功能,如果此特定查询是上下文实例将运行的唯一查询,这可能就足够了。如果没有,您可以向该部分添加更多条件if(command.CommandText.StartsWith("SELECT")
.
另一种方法是将特定查询标记为.TagWith https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.entityframeworkqueryableextensions.tagwith?view=efcore-3.1并在拦截器中查找标签文本:
if (command.CommandText.StartsWith("SELECT")
&& command.CommandText.Contains("my tagged text"))
{
command.CommandText += " OPTION (OPTIMIZE FOR UNKNOWN)";
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)