如何在EF6查询中使用TVP?(不是存储过程)

Tri*_*tan 7 performance entity-framework table-valued-parameters sql-execution-plan azure-sql-database

我在具有复杂EF6查询的Azure上遇到SQL性能问题.环境配置为弹性池.在开发区域,eDTU限制经常通过CPU使用率来命中,我将其归因于查询计划生成.

该应用程序相当通用,因此EF查询非常复杂,但在查询的内容中,通常有一个子查询通常具有IN子句.

SELECT Id FROM Event E WHERE E.Name IN (@p__linq__1, @p__linq__2, @p__linq__3)
Run Code Online (Sandbox Code Playgroud)

要么

SELECT Id FROM Event E WHERE E.Name IN (@p__linq__4, @p__linq__5)
Run Code Online (Sandbox Code Playgroud)

虽然查询的其余部分是相同的,但是会生成新的SQL查询计划,因为文本因参数的数量而不同.

以前,在另一个项目中,我通过在连接中使用TVP而不是where子句来增加计划重用.

SELECT Id FROM Event E INNER JOIN @p_tvp_strings T ON E.Name = T.[Value]
Run Code Online (Sandbox Code Playgroud)

我无法通过IQueryable方式解决如何在EF中执行此操作.

我已经尝试创建一个Datatable并解析它作为参数但context.Database.SqlQuery不返回IQueryable.它立即执行命令.

var nameArray = new string[]
{
  "Bob", "Fred", "Bill",
};

var nameTable = CreateDataTable(nameArray);

var parameter = new SqlParameter("tvp", nameTable);
parameter.SqlDbType = SqlDbType.Structured;
parameter.TypeName = "StringSet";

var names = context.Database.SqlQuery<string>("SELECT [Value] FROM @tvp", parameter).AsQueryable();
var people = context.People.Where(p => names.Contains(p.Name)).ToList();
Run Code Online (Sandbox Code Playgroud)

不幸的是,这导致生成两个查询.

declare @p3 dbo.StringSet 
insert into @p3 values(N'Bob')
insert into @p3 values(N'Fred')
insert into @p3 values(N'Bill')

exec sp_executesql N'SELECT [Value] FROM @tvp',N'@tvp [StringSet] READONLY',@tvp=@p3

SELECT 
  [Extent1].[Id] AS [Id], 
  [Extent1].[Name] AS [Name], 
  [Extent1].[Title] AS [Title], 
  [Extent1].[Age] AS [Age]
FROM 
  [dbo].[People] AS [Extent1]
WHERE 
  [Extent1].[Name] IN (N'Bill', N'Bob', N'Fred')
Run Code Online (Sandbox Code Playgroud)

有没有人知道如何在使用EF时在WHERE子句中使用TVP?