EF Core, FromSqlRaw with USE HINT



我很困惑!
我有一个ASP。. Net Core 3 WebApi应用程序,这工作得很好:

var results = _context.Users.ToList();

但是,如果我尝试添加"HINT";

var results = _context.Users.FromSqlRaw("SELECT * FROM t_user OPTION(USE HINT('ENABLE_PARALLEL_PLAN_PREFERENCE'))").ToList();

…然后抛出这个异常…

Incorrect syntax near the keyword 'OPTION'.
Database 'HINT' does not exist. Make sure that the name is entered correctly.

为什么这个SQL可以在SQL Server Management Studio中成功运行,但是却被WebApi误解了?


Update # 1

该死。当你告诉EF Core使用Raw SQL时,它实际上把SQL放入子句中,这就是为什么我看到错误。

所以,这是(完全有效的)SQL,我试图运行:

SELECT * FROM t_user 
OPTION(USE HINT('ENABLE_PARALLEL_PLAN_PREFERENCE'))

. .但是,查看SQL Server Profiler, EF Core实际上正在尝试此SQL,这是无效的…

SELECT [u].[user_id], [u].[user_name]
FROM (
SELECT * FROM t_user 
OPTION(USE HINT('ENABLE_PARALLEL_PLAN_PREFERENCE'))
) AS [u]

该死的……

那么我们如何使用EF Core的提示呢?


更新# 2

因为我使用的是EF Core,所以我按照这篇微软文章中的说明将DbCommandInterceptor添加到我的查询中。

在他们的例子中,它拦截SQL并将" OPTION (ROBUST PLAN)"附加到字符串。它显示它正在尝试运行以下SQL:

SELECT [u].[user_id], [u].[user_name]
FROM t_user 
OPTION (ROBUST PLAN)

如果我以Microsoft为例,并将其更改为使用myHINT,那么我仍然得到相同的错误,它说';数据库'HINT'不存在。">

private static void ManipulateCommand(DbCommand command)
{
if (command.CommandText.StartsWith("-- Use hint: robust plan", StringComparison.Ordinal))
{
command.CommandText += " OPTION(USE HINT('ENABLE_PARALLEL_PLAN_PREFERENCE'))";
}
}

啊!为什么我不能使用提示?

似乎由于某种原因USE HINT('ENABLE_PARALLEL_PLAN_PREFERENCE')被视为USE <db_name>

使用

将数据库上下文更改为SQL Server中的指定数据库或数据库快照。

那么错误:"Database 'HINT' does not exist."是完全有意义的。


现在对于ENABLE_PARALLEL_PLAN_PREFERENCE,它是未记录的查询提示:

https://github.com/MicrosoftDocs/sql-docs/issues/2442

不幸的是,我们不得不拒绝添加关于ENABLE_PARALLEL_PLAN_PREFERENCE的信息。这是一个未记录的查询提示,用于故障排除目的,并在Microsoft Support的指导下使用。我们通常不会故意记录某些查询提示/跟踪标志,因为这可能会导致性能问题或其他意想不到的后果。

因此,在将其设置为默认值或在生产代码中使用时请谨慎。

您可以尝试使用OPTION(QUERYTRACEON 8649),它的行为将与前面提到的ENABLE_PARALLEL_PLAN_REFERENCE相同,但它将需要管理员权限:

private static void ManipulateCommand(DbCommand command)
{
if (command.CommandText.StartsWith("-- Use hint: robust plan", StringComparison.Ordinal))
{
command.CommandText += " OPTION(QUERYTRACEON 8649)";
}
}

总结:在应用程序代码中设置这个提示之前,我建议解决真正的潜在问题(maxdop/并行的成本阈值/…)

编辑:

原始SQL查询

使用LINQ组合要求原始SQL查询是可组合的,因为EF Core会将提供的SQL视为子查询。可以以SELECT关键字开始的SQL查询。此外,传递的SQL不应该包含任何对子查询无效的字符或选项,例如:

后面的分号

在SQL Server上,后面的查询级提示(例如OPTION (HASH JOIN))

在SQL Server上,ORDER BY子句没有与SELECT子句中的OFFSET 0或TOP 100%一起使用

当你告诉Ef core你的查询的输出是一个实体,然后EF包装你的查询到该实体,但如果你为你的查询定义了一个Keyless Entity Types, EF首先执行查询,然后映射结果到你的模型。

首先创建像用户模型一样的模型:

public class KeyLessUser
{
public string UserId { get; set; }
public string UserName { get; set; }
}

HasNoKey:

添加到DbContext
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<KeyLessUser>().HasNoKey();
}

最后像这样执行查询:

var results = _context.Set<KeyLessUser>().FromSqlRaw("SELECT * FROM t_user OPTION(USE HINT('ENABLE_PARALLEL_PLAN_PREFERENCE'))").ToList();

经过测试,工作正常。

相关内容

  • 没有找到相关文章

最新更新