C# EF查询计数时间比完整列表时间长几个数量级
我在EF中有一个查询,它在两个集合之间执行交集并计算返回的行数。这不是一个非常复杂的查询,生成的SQL很简单 但是,使用EF执行此查询花费的时间太长C# EF查询计数时间比完整列表时间长几个数量级,c#,sql,entity-framework-6,C#,Sql,Entity Framework 6,我在EF中有一个查询,它在两个集合之间执行交集并计算返回的行数。这不是一个非常复杂的查询,生成的SQL很简单 但是,使用EF执行此查询花费的时间太长 在SSMS(20ms)中运行此查询不需要时间,但当我通过EF运行它时,它需要大约800ms,即使底层SQL是相同的。这对我来说不是指数问题 我已经在SQL事件探查器和EF事件探查器中查看了生成的SQL,生成的SQL与预期的一样 如果我使用.SqlQuery通过EF运行查询文本,它也会执行 大约20毫秒后 执行顺序不是问题,无论我运行哪个顺序.Sq
- 在SSMS(20ms)中运行此查询不需要时间,但当我通过EF运行它时,它需要大约800ms,即使底层SQL是相同的。这对我来说不是指数问题
- 我已经在SQL事件探查器和EF事件探查器中查看了生成的SQL,生成的SQL与预期的一样
- 如果我使用
通过EF运行查询文本,它也会执行 大约20毫秒后.SqlQuery
- 执行顺序不是问题,无论我运行哪个顺序
,中的实际EF查询都会重现EF perf问题(即它似乎不是SQL查询缓存问题).SqlQuery
- 如果我从查询中删除计数(例如使用
),它将在大约20毫秒内执行(但是,如果交叉点足够大,这实际上不是一个可行的解决方案).ToArray().count()
- 查询计划似乎是合理的,它全部在索引中,并且在EF之外表现良好
exec sp_executesql
和参数化来稍微整理它。当我在基于代码的查询中复制这一点时,我能够重现EF查询的糟糕性能(这很好)。然而,在任何使用SSMS的情况下,它仍然运行得很快
我的假设是,参数嗅探的问题被隔离到同一查询的第一次执行。然而,进一步的阅读证明这一假设是无效的。我可以通过在exec sp_executesql
字符串的末尾添加选项(重新编译)
来证明这是由参数嗅探引起的(正如@MitchWheat所建议的)。这使得它在一个合理的时间框架内执行
我仍然不知道如何用EF解决这个问题,但至少我知道它是什么
辅助胶
EF查询
var query = (from c in ctx.RuleCurrentMembershipCache
where c.RuleId == baseRule
where c.Direction == Direction.In
select c.Key)
.Distinct()
.Intersect((from c in ctx.RuleCurrentMembershipCache
where c.RuleId == ruleId
where c.Direction == Direction.In
select c.Key).Distinct());
query.ToArray().Count();//fast
query.Count();//slow
生成的SQL
SELECT [GroupBy1].[A1] AS [C1]
FROM (
SELECT COUNT(1) AS [A1]
FROM (
SELECT [Distinct1].[Key] AS [Key]
FROM (
SELECT DISTINCT [Extent1].[Key] AS [Key]
FROM [RuleCurrentMembershipCache] AS [Extent1]
WHERE ([Extent1].[RuleId] = 'c0cdd83d-0cad-430d-bb6a-7abdbf115856' /* @p__linq__0 */)
AND (1 = CAST([Extent1].[Direction] AS int)
)
) AS [Distinct1]
INTERSECT
SELECT [Distinct2].[Key] AS [Key]
FROM (
SELECT DISTINCT [Extent2].[Key] AS [Key]
FROM [RuleCurrentMembershipCache] AS [Extent2]
WHERE ([Extent2].[RuleId] = '6d97cf92-8a57-4de2-8756-0abe6977eb7d' /* @p__linq__1 */)
AND (1 = CAST([Extent2].[Direction] AS int))
) AS [Distinct2]
) AS [Intersect1]
) AS [GroupBy1]
模式
CREATE TABLE [RuleCurrentMembershipCache](
[RuleId] [uniqueidentifier] NOT NULL,
[Key] [int] NOT NULL,
[Timestamp] [datetimeoffset](7) NOT NULL,
[Direction] [int] NOT NULL,
CONSTRAINT [PK_RuleCurrentMembershipCache] PRIMARY KEY CLUSTERED
(
[RuleId] ASC,
[Key] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_RuleId] ON [RuleCurrentMembershipCache]
(
[RuleId] ASC
)
INCLUDE ( [Direction],
[Key]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
“在SSMS(20ms)中运行此查询不需要时间,但当我通过 EF即使基础SQL相同,也需要大约800毫秒的时间。 在我看来,这个问题不是指数。” 这通常是参数嗅探的症状。SSMS在连接上设置选项,使查询在执行时重新编译(因此SSMS的执行时间总是很短)
规范参考:“这个查询在SSMS(20ms)中运行不需要时间,但是当我通过EF运行它时,它需要大约800ms,即使底层SQL是相同的。这对我来说,问题不是索引。”-通常是参数嗅探的症状…@MitchWheat我认为这可能有点奇怪。为了隔离它,我尝试通过手动执行SQL两次来启动系统,一次使用原始SQL命令,然后使用EF查询。我的理解是,参数嗅探应该使第一个变慢。然而,无论我以何种方式订购,EF总是慢的。还有什么我应该试试的吗?@MitchWheat我做了更多的研究,你完全正确,这是由参数嗅探引起的。如果你发布,我会接受(因为这是一个为什么的问题)。谢谢您的帮助。@LukeMcGregor我想知道使用contains pr any而不是intersect重新格式化查询是否有助于提高性能,并避免参数嗅探altogether@TheVedge事实上,它很容易受到完全相同的问题的影响,但是这种变化确实让我减少了一点查询时间,因为(我没有意识到)所以谢谢:)