LINQ查询性能低下

时间:2015-02-11 06:54:37

标签: c# .net sql-server linq

我有这个来自在Cold Fusion上运行的旧系统的t-sql查询。此查询返回记录的时间不到一秒。

select  dateDiff(month, dateAdd(hour, 11, createdAt), {ts '2015-02-28 23:59:59'}) p, count(*) c 
from    account 
where   createdAt <= {ts '2015-02-28 23:59:59'} 
and accountType = 'business' 
and dateDiff(month, dateAdd(hour, 11, createdAt), {ts '2015-02-28 23:59:59'}) <12 
group by    dateDiff(month, dateAdd(hour, 11, createdAt), {ts '2015-02-28 23:59:59'}) 
order by    dateDiff(month, dateAdd(hour, 11, createdAt), {ts '2015-02-28 23:59:59'})

我现在使用.NET和LINQ将其转换为新系统。 我设法写了这个LINQ查询,它给了我相同的结果。

from a in db.Accounts
where SqlFunctions.DateDiff("Month", SqlFunctions.DateAdd("Hour", 11, a.createdAt), "2015-02-28 23:59:59") < 12
&& a.accountType == "business"
group a by SqlFunctions.DateDiff("Month", a.createdAt, "2015-02-28 23:59:59") into grp
orderby SqlFunctions.DateDiff("Month", grp.FirstOrDefault().createdAt, "2015-02-28 23:59:59")
select new ProgressViewModel.Data
{
     date = SqlFunctions.DateDiff("Month", grp.FirstOrDefault().createdAt, "2015-02-28 23:59:59"),
     amount = grp.Count()
});

但是,此查询运行时间不少于5秒,而第一个查询(t-sql)则需要不到1秒。

通过使用Glimpse,我们可以看到LINQ查询生成的t-sql。它有多个子选择,比快速查询长5倍。

我如何改进LINQ查询?

4 个答案:

答案 0 :(得分:2)

在分组之前尝试这样的事情将其带入内存:

from ca in (
    from a in db.Accounts
    where SqlFunctions.DateDiff("Month", SqlFunctions.DateAdd("Hour", 11, a.createdAt), "2015-02-28 23:59:59") < 12 && a.accountType == "business"
    select a.createdAt).ToArray()
group a by new /* month diff */ into grp
orderby grp.Key
select new ProgressViewModel.Data
{
    date = grp.key,
    amount = grp.Count()
});

答案 1 :(得分:1)

我真的怀疑你确实想在代码中的任何一点使用FirstOrDefault()

BTW看起来您正在使用LinqToSQL作为您的Linq提供商。那东西是讨厌,低效和彻头彻尾的马车。如果可能的话,你应该切换到EntityFramework

考虑到......也许你应该试试这个......

var date = new Date(2015, 2, 28).AddDays(1);
var query = from account in context.Accounts
            where account.CreatedAt < date
            where account.accountType == "business"
            group account by 
                   SqlFunctions.DateDiff(
                            "Month", 
                             SqlFunctions.DateAdd(
                                   "Hour", 11, a.createdAt), 
                             date)
            into g
            where g.Key < 12
            order by g.Key ascending
            select new 
            {
                MonthsAgo = g.Key,
                Count = g.Count(),
            };

答案 2 :(得分:0)

快速浏览一下,我会调查您的部分grp.FirstOrDefault - 这真的是您想要做的吗?

答案 3 :(得分:-1)

在这种情况下,我肯定会选择参数化的存储过程。您还应该考虑在所需的表上创建覆盖索引。这些步骤通常会以非常显着的数量提升性能。