EF查询的计数数量级要长于完全列出的数量级

时间:2014-09-22 03:25:31

标签: c# sql entity-framework-6

我在EF中有一个查询,它正在执行两个集合之间的交集并计算返回的行数。它不是一个非常复杂的查询,生成的SQL很简单。

然而,使用EF执行此查询的时间太长了。

  • 此查询没有时间在SSMS(20ms)中运行,但是当我通过EF运行它时,即使底层SQL是相同的,它也需要大约800ms。这对我来说这个问题不是指数。
  • 我查看了Sql Profiler和EF Profiler中生成的SQL,生成的SQL是预期的。
  • 如果我使用.SqlQuery<int>通过EF运行查询文本,它也会执行 在大约20ms。
  • 执行顺序不是我运行的任何顺序.SqlQuery<int>和实际EF查询重现EF perf问题(即它似乎不是SQL查询缓存问题)的问题。
  • 如果我从查询中删除了计数(例如使用.ToArray().Count()),它会在大约20ms内执行(但如果交叉点足够大,这不是一个可行的解决方案)
  • 查询计划似乎合情合理,它全部在索引中,并且在EF
  • 之外表现良好

有没有人知道任何可能导致这种行为的事情,或者我可以尝试诊断它的任何其他事情?

修改

我更多地使用查询并注意到生成的SQL在EF Profiler中与SQL Profiler略有不同,EF Profiler通过从查询中删除exec sp_executesql和参数化来稍微整理一下。当我在基于代码的查询中复制它时,我能够重现EF查询的不良性能(这很好)。然而,在使用SSMS的任何情况下它仍然运行得很快。

我的假设是参数嗅探的问题被隔离到第一次执行相同的查询。然而,进一步阅读证明这一假设无效。我能够通过将OPTION (RECOMPILE)添加到exec sp_executesql字符串的末尾来证明这是由参数嗅探(如@MitchWheat建议)引起的。这使它在合理的时间范围内执行。

我还不确定如何用EF解决这个问题,但至少我知道它是什么。

支持Gumph

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]

1 个答案:

答案 0 :(得分:2)

  

“此查询没有时间在SSMS(20ms)中运行,但是当我通过它运行时   即使基础SQL相同,EF大约需要800毫秒。   这对我来说这个问题不是指数。“

这通常是参数嗅探的症状。 SSMS在连接上设置选项,这些选项在执行时会导致查询被重新编译(因此SSMS的执行时间总是很短)。

规范参考:Slow in the Application, Fast in SSMS?