![](/img/trans.png)
[英]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.