为什么当我重用 Linq 查询变量时会发生微小的性能提升

本文关键字:性能 Linq 变量 查询 为什么 | 更新日期: 2023-09-27 18:35:25

环境:
SQL CE
Windows Phone 7.5 及更高版本
Visual Studio 2012 更新 3
示例:所有任务30个,今天任务10个,明天任务10个,过期任务
10

要求
一个待办事项应用程序,需要在首页显示3个数字,所有任务,今天任务,明天任务。

原始代码:

private Stopwatch sw=new Stopwatch();
using (TasksDataContext db = new TasksDataContext(TasksDataContext.DBConnectionString))
{
     sw.Start();
     var allTask = db.TasksItems.Where(t => t.Title != null && t.IsCompleted != true);
     System.Diagnostics.Debug.WriteLine( "allTask:"+sw.ElapsedMilliseconds.ToString());
     Taskamount = allTask.Count();
     var todayTask = db.TasksItems.Where(t => t.DueDate != null & t.DueDate.Value.Date == DateTime.Now.Date & t.IsCompleted == false);
     System.Diagnostics.Debug.WriteLine("todayTask:" + sw.ElapsedMilliseconds.ToString());
     todayNumber = todayTask.Count();
     var tomorrowTask = db.TasksItems.Where(t => t.DueDate != null & t.DueDate.Value.Date == DateTime.Now.Date.AddDays(1) & t.IsCompleted == false);
     System.Diagnostics.Debug.WriteLine("tomorrowTask:" + sw.ElapsedMilliseconds.ToString());
     sw.Stop();
     tomorrowNumber = tomorrowTask.Count();
}

最新代码:

private Stopwatch sw=new Stopwatch();
using (TasksDataContext db = new TasksDataContext(TasksDataContext.DBConnectionString))
{
     sw.Start();
     var allTask = db.TasksItems.Where(t => t.Title != null && t.IsCompleted != true);
     System.Diagnostics.Debug.WriteLine( "allTask:"+sw.ElapsedMilliseconds.ToString());
     Taskamount = allTask.Count();
     var todayTask = allTask.Where(t => t.DueDate != null & t.DueDate.Value.Date == DateTime.Now.Date & t.IsCompleted == false);
     System.Diagnostics.Debug.WriteLine("todayTask:" + sw.ElapsedMilliseconds.ToString());
     todayNumber = todayTask.Count();
     var tomorrowTask = allTask.Where(t => t.DueDate != null & t.DueDate.Value.Date == DateTime.Now.Date.AddDays(1) & t.IsCompleted == false);
     System.Diagnostics.Debug.WriteLine("tomorrowTask:" + sw.ElapsedMilliseconds.ToString());
     sw.Stop();
     tomorrowNumber = tomorrowTask.Count();
}

调试输出
源语言:
第一次:
全部任务:9
今天任务:165
明天任务:221

第二次:
全部任务:10
今天任务:179
明天任务:233

第三次:
全部任务:14
今天任务:168
明天任务:225

第四次:
全部任务:8
今日任务:181
明天任务:236

第五次:
全部任务:8
今天任务:166
明天任务:221


最近的:
第一次:
全部任务:9
今天任务:157
明天任务:216

第二次:
全部任务:8
今天任务:163
明天任务:219

第三次:
全部任务:8
今天任务:161
明天任务:216

第四次:
全部任务:8
今天任务:164
明天任务:222

第五次:
全部任务:9
今天任务:153
明天任务:210

为什么我修改代码
由于今天任务和明天任务是所有任务的子集。我认为重用 linq 查询变量将提高性能。结果显示出微小的提升。

是什么让我感到困惑:
我读了MSDN中的linq部分,它说:

在 LINQ 中,查询的执行与查询本身不同; 换句话说,您没有通过创建 查询变量。

这让我想到了一个问题:为什么它会快一点?根据MSDN的说法:linq查询的重用不会提高性能,但会损害性能。

当编译器运行以下代码时:

var todayTask = allTask.Where(t => t.DueDate != null & t.DueDate.Value.Date == DateTime.Now.Date & t.IsCompleted == false);

它将执行 2 个操作,一个用于所有任务,一个用于 todayTask。但是当使用"db.taskitems.Where()"时,它只执行一次操作。

我的问题
1. 为什么它更快?(编译器是否在编译时优化了我的代码?
2.有没有更好的方法来提高速度?

为什么当我重用 Linq 查询变量时会发生微小的性能提升

速度可能是由于查询(t => t.Title != null)中的额外条件allTask而发生的。这不包括在todayTasktomorrowTask中。

为了加快速度,您可以尝试将Count与谓词一起使用并删除冗余条件:

var allTask = [...];
Taskamount = allTask.Count();
todayNumber = allTask.Count(t => t.DueDate != null && t.DueDate.Value.Date == DateTime.Now.Date);
tomorrowNumber = allTask.Count(t => t.DueDate != null && t.DueDate.Value.Date == DateTime.Now.Date.AddDays(1));

您也可以尝试GroupBy

var result = allTask.GroupBy(x => 1, x => x, (key, g) => new
{
    All = g.Count(),
    Today = g.Count(t => t.DueDate != null && t.DueDate.Value.Date == DateTime.Now.Date),
    Tomorrow = g.Count(t => t.DueDate != null && t.DueDate.Value.Date == DateTime.Now.Date.AddDays(1))
}).Single();

这应该对所有聚合执行一个查询,但我不知道所有 linq 驱动程序是否都支持它。