2

我很困惑 !
我有一个 ASP.Net Core 3 WebApi 应用程序,它工作正常:

var results = _context.Users.ToList();

但是,如果我尝试HINT在 SQL 中添加“”...

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 误解了?


更新#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,所以我按照这篇 Microsoft 文章DbCommandInterceptor中的说明在我的查询中添加了一个。

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

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

如果我以 Microsoft 为例,并将其更改为使用我的提示,那么我仍然会收到相同的错误,即“数据库‘提示’不存在。

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'))";
    }
}

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

4

2 回答 2

1

似乎由于某种原因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 支持的指导下使用。我们通常不会故意记录某些查询提示/跟踪标志,因为它可能会导致性能问题或其他意外后果。

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

您可以尝试使用OPTION(QUERYTRACEON 8649)which 的行为与上述相同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/Cost Threshold for Parallelism/...)


编辑:

原始 SQL 查询

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

尾随分号

在 SQL Server 上,尾随查询级别提示(例如,OPTION (HASH JOIN))

在 SQL Server 上,未与 SELECT 子句中的 OFFSET 0 OR TOP 100 PERCENT 一起使用的 ORDER BY 子句

于 2021-02-22T12:16:36.843 回答
1

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

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

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

            public string UserName { get; set; }

        }

DbContext并将其添加到HasNoKey

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();

测试并且工作正常。

于 2021-02-23T14:58:38.647 回答