我很困惑!
我有一个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
,它是未记录的查询提示:
不幸的是,我们不得不拒绝添加关于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();
经过测试,工作正常。