大家好,我遇到了性能问题 当我使用在查询
中声明的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,所有这些差异。
答案 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,则执行计划中没有区别。