[英]Perform 'select * from (select * from …)' query in ef core 2.2
[英]EF Core takes a lot of time, sometimes, to perform SELECT query
我正在使用 EF Core 6 与 SQL 服务器数据库。 有时,SELECT 查询的执行时间超过 30 秒,并且超时。
如果我执行由 EF Core 生成的完全相同的 SQL(使用完全相同的参数,在相同的数据库上,超时后仅几秒),它需要不到一秒的时间。
在整个期间,DB 服务器的 CPU 使用率 < 30%。
在 SQL Server Management Studio 上运行 SQL 查询,我可以看到执行计划是理想的(即它使用索引等)。
所以我担心可能会有一些锁定阻止数据库返回查询结果。
有没有办法向 EF Core 指定查询的隔离级别,甚至一些并发/锁定策略?
在我的具体场景中,有脏读或不完全最新的读取是可以的,因为我们有适当的程序来在后续轮查询中检索干净的数据。
谢谢
当 SQL Server 可能因为Parameter Sniffing而减慢查询时,这不是一个新问题。 可以通过将参数转换为常量或在查询末尾添加OPTION(RECOMPILE)来解决问题。 此答案将DbCommandInterceptor
添加到DbContextOptions
并将OPTION(RECOMPILE)
提示附加到特定查询。
配置 DbContext
builder.UseSqlServer(connectionString)
.UseRecompileExtensions(); // registering interceptor
如何在查询中使用:
var name = "SomeName";
var result = context.SomeItems
.Where(x => x.Name == name)
.WithRecompile() // it marks query as a query which need RECOMPILE query hint
.ToList();
然后将以下 SQL 发送到 SQL Server:
SELECT [s].[Id], [s].[Name]
FROM [SomeItems] AS [s]
WHERE [s].[Name] = @__name_0
OPTION(RECOMPILE)
以及扩展的实现:
我已将所有内容放入一个静态类中以简化答案。 在 EF Core 6 上测试,但也适用于较低版本。
public static class RecompileExtensions
{
private const string RecompileTag = "recompile_query_tag";
private const string RecompileComment = "-- " + RecompileTag + "\r\n";
public static DbContextOptionsBuilder UseRecompileExtensions(this DbContextOptionsBuilder builder)
{
return builder.AddInterceptors(RecompileInterceptor.Instance);
}
public static IQueryable<T> WithRecompile<T>(this IQueryable<T> query)
{
return query.TagWith(RecompileTag);
}
private class RecompileInterceptor : DbCommandInterceptor
{
public static RecompileInterceptor Instance = new();
public override ValueTask<InterceptionResult<DbDataReader>> ReaderExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result,
CancellationToken cancellationToken = new CancellationToken())
{
CorrectCommand(command);
return base.ReaderExecutingAsync(command, eventData, result, cancellationToken);
}
public override InterceptionResult<DbDataReader> ReaderExecuting(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result)
{
CorrectCommand(command);
return base.ReaderExecuting(command, eventData, result);
}
private static void CorrectCommand(DbCommand command)
{
var newQuery = command.CommandText.Replace(RecompileComment, "");
// if query was changed, we have to append RECOMPILE option
if (!ReferenceEquals(newQuery, command.CommandText))
{
// remove rest of the comment
if (newQuery.StartsWith("\r\n"))
newQuery = newQuery.Substring(2);
newQuery += "\r\nOPTION(RECOMPILE)";
command.CommandText = newQuery;
}
}
}
}
不建议重新编译,它可能会损害正常运行的应用程序。 对于大规模数据,我个人推荐使用DBQuery或者Simple ADO.net
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.