在linq查询中优化dateTime

时间:2015-04-16 08:32:27

标签: c# asp.net sql-server linq entity-framework

大家好,我遇到了性能问题 当我使用在查询

中声明的dateTime运行此查询时
var temp = (from p in db.BEM_EVT_FULL
                      where (p.date_reception > new DateTime(2015,01,01))
                      group p by p.mc_object into g
                      orderby g.Count() descending
                      select new StringIntType
                      {
                          str = g.Key,
                          nbr = g.Count()}).Take(50).ToList();

在sql server profiler中,它被翻译为该查询

SELECT TOP (50) 
[Project1].[C3] AS [C1], 
[Project1].[mc_object] AS [mc_object], 
[Project1].[C2] AS [C2]
FROM ( SELECT 
    [GroupBy1].[A1] AS [C1], 
    [GroupBy1].[A2] AS [C2], 
    [GroupBy1].[K1] AS [mc_object], 
    1 AS [C3]
    FROM ( SELECT 
        [Extent1].[mc_object] AS [K1], 
        COUNT(1) AS [A1], 
        COUNT(1) AS [A2]
        FROM [dbo].[BEM_EVT_FULL] AS [Extent1]
        WHERE [Extent1].[date_reception] > convert(datetime2, '2015-01-01 00:00:00.0000000', 121)
        GROUP BY [Extent1].[mc_object]
    )  AS [GroupBy1]
)  AS [Project1]
ORDER BY [Project1].[C1] DESC

它可以正常工作在1s以下执行

现在当我在查询外面声明DateTime并运行此查询

DateTime dt = new DateTime(2015,01,01);

        var temp = (from p in db.BEM_EVT_FULL
                      where (p.date_reception > dt)
                      group p by p.mc_object into g
                      orderby g.Count() descending
                      select new StringIntType
                      {
                          str = g.Key,
                          nbr = g.Count()
                      }).Take(50).ToList();

在sql server profiler中,它被翻译为该查询

exec sp_executesql N'SELECT TOP (50) 
[Project1].[C3] AS [C1], 
[Project1].[mc_object] AS [mc_object], 
[Project1].[C2] AS [C2]
FROM ( SELECT 
    [GroupBy1].[A1] AS [C1], 
    [GroupBy1].[A2] AS [C2], 
    [GroupBy1].[K1] AS [mc_object], 
    1 AS [C3]
    FROM ( SELECT 
        [Extent1].[mc_object] AS [K1], 
        COUNT(1) AS [A1], 
        COUNT(1) AS [A2]
        FROM [dbo].[BEM_EVT_FULL] AS [Extent1]
        WHERE [Extent1].[date_reception] > @p__linq__0
        GROUP BY [Extent1].[mc_object]
    )  AS [GroupBy1]
)  AS [Project1]
ORDER BY [Project1].[C1] DESC',N'@p__linq__0 datetime2(7)',@p__linq__0='2015-01-01 00:00:00'

由于DateTime声明,我需要知道应该做什么更改来声明DateTime outisde查询,并且获得与第一个查询相同的性能,因此需要大约5百万才能得到exectued,所有这些差异。

4 个答案:

答案 0 :(得分:1)

我猜你的表中有很多行,值2015-01-01 00:00:00提供足够的过滤来排除很多行(比如10个中的8个),值得使用相应的索引。

使用变量,与简单的表扫描相比,查询优化器不知道变量是否会提供足够的过滤。 它可能判断它不值得使用索引(特别是如果索引的INCLUDE子句与查询无关。According to your previous question,可能就是这种情况)

由于“参数嗅探”

,它也可能生成了错误的查询计划

无论如何,您可以尝试使用专用的查询拦截器来引入强制“OPTION RECOMPILE”。看到 https://stackoverflow.com/a/26762756/1236044

答案 1 :(得分:0)

这个(我相信)的原因是在第一个场景中,DateTime是一个编译时常量,但是在第二个场景中它不是,因此EF必须将它作为参数传递。

答案 2 :(得分:0)

我的猜测是,使用常量值,SQL编译器知道如何创建最有效的计划,但是使用参数,它不会,所以它必须猜测,任何可能猜得很糟糕。由于第一个查询只返回50条记录而仍然需要几乎一分钟才能运行,我认为在[date_reception][mc_object]上添加索引(或重建索引,如果索引已经存在)应该会有所帮助。如果那些不能正常工作,您可能会被迫手动构建SQL而不是使用Linq,因为您无法控制Linq生成的SQL。

答案 3 :(得分:0)

尝试找出执行计划的差异。在this experiment中,由于列被声明为日期时间而比特被声明为不同,因此它是不同的。在一种情况下,它是一个内联语句,另一种情况下是一个声明的变量。如果您将该字段声明为datetime2,则执行计划中没有区别。

相关问题