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

时间:2018-04-16 03:41:55

标签: performance entity-framework azure-sql-database sql-execution-plan table-valued-parameters

我在使用复杂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)

OR

SELECT Id FROM Event E WHERE E.Name IN (@p__linq__4, @p__linq__5)

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

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

SELECT Id FROM Event E INNER JOIN @p_tvp_strings T ON E.Name = T.[Value]

我无法通过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();

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

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')

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

0 个答案:

没有答案