0

環境:
SQL CE
Windows Phone 7.5 以降
Visual Studio 2012 update 3
サンプル:全タスク 30 件、今日のタスク 10 件、明日のタスク 10 件、期限切れのタスク 10 件

要件:
To Do アプリで、ホームページに 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();
}

debug output
original:
1回目:
allTask​​:9
todayTask:165 TomorrowTask
:221

2回目:
allTask​​:10
今日Task:179
明日Task:233

3回目:
allTask​​:14
今日Task:168
明日Task:225

4回目:
allTask​​:8
今日Task:181
明日Task:236

5 回目:
allTask​​:8
今日Task:166
明日Task:221


最新:
1 回目:
allTask​​:9
今日Task:157
明日Task:216

2回目:
allTask​​:8
今日Task:163
明日Task:219

3回目:
allTask​​:8
今日Task:161
明日Task:216

4回目:
allTask​​:8
今日Task:164
明日Task:222

5回目:
allTask​​:9
今日Task:153
明日Task: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 つの操作を行います。1 つは allTask​​ 用で、もう 1 つは todayTask 用です。しかし、「db.taskitems.Where()」を使用すると、単一の操作しか実行されません。

私の質問
1.なぜ速いのですか? (コンパイラはコンパイル時にコードを最適化しますか?)
2. 速度を上げるためのより良い方法はありますか?

4

1 に答える 1

0

allTaskこの高速化は、クエリ ( )の余分な条件が原因で発生する場合がありますt => t.Title != null。これは と には含まれませ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();

これはすべての集計に対して 1 つのクエリを実行する必要がありますが、すべての linq ドライバーでサポートされているかどうかはわかりません。

于 2013-10-14T07:10:08.733 に答える