C# Linq-内存中连接与EF连接

C# Linq-内存中连接与EF连接,c#,performance,entity-framework,linq,join,C#,Performance,Entity Framework,Linq,Join,使用EF 6和SQL 2014 假设您有一个索引良好且规范化的数据库。将实体拉入内存然后在IEnumerables上执行连接是“更好”还是让EF通过IQueryable进行连接 通过更好的->更快的执行时间,减少对数据库的读取,减少内存的使用 内存中的示例: using (var context = myDbContext()) { var table1 = await context.Table1.ToListAsync(); var table2 = await contex

使用EF 6和SQL 2014

假设您有一个索引良好且规范化的数据库。将实体拉入内存然后在IEnumerables上执行连接是“更好”还是让EF通过IQueryable进行连接

通过更好的->更快的执行时间,减少对数据库的读取,减少内存的使用

内存中的示例:

using (var context = myDbContext())
{
    var table1 = await context.Table1.ToListAsync();
    var table2 = await context.Table2.ToListAsync();
    var table3 = await context.Table3.ToListAsync();

    var resultSet = table1
        .Join(table2, t1 => t1.Id, t2 => t2.Table1Id, (t1,t2) => new {t1, t2})
        .Join(table3, x => x.t2.Table2Id, t3 => t3.Table2Id, (x, t3) => new { x.t1, x.t2, t3})
        .ToList();
}
using (var context = myDbContext())
{
    var resultSet = await context.Table1
        .Join(context.Table2, t1 => t1.Id, t2 => t2.Table1Id, (t1,t2) => new {t1, t2})
        .Join(context.Table3, x => x.t2.Table2Id, t3 => t3.Table2Id, (x, t3) => new { x.t1, x.t2, t3})
        .ToListAsync();
}
示例EF:

using (var context = myDbContext())
{
    var table1 = await context.Table1.ToListAsync();
    var table2 = await context.Table2.ToListAsync();
    var table3 = await context.Table3.ToListAsync();

    var resultSet = table1
        .Join(table2, t1 => t1.Id, t2 => t2.Table1Id, (t1,t2) => new {t1, t2})
        .Join(table3, x => x.t2.Table2Id, t3 => t3.Table2Id, (x, t3) => new { x.t1, x.t2, t3})
        .ToList();
}
using (var context = myDbContext())
{
    var resultSet = await context.Table1
        .Join(context.Table2, t1 => t1.Id, t2 => t2.Table1Id, (t1,t2) => new {t1, t2})
        .Join(context.Table3, x => x.t2.Table2Id, t3 => t3.Table2Id, (x, t3) => new { x.t1, x.t2, t3})
        .ToListAsync();
}

你怎么知道一辆车比另一辆车快?驾驶两辆车,比较时间

通常,数据库在连接数据方面比内存中的Linq更有效(由于预先计算的索引、散列等),但在某些情况下,内存中的连接速度肯定会更快。但是,当您没有将所有数据都拉入内存时,通过连接获得的数据更少的好处可能会比连接中的任何性能改进产生更大的差异


所以没有一个明确的答案。从有效的东西开始,然后通过测量更改前后的时间来关注性能改进。

如何知道一辆车是否比另一辆车快?驾驶两辆车,比较时间

通常,数据库在连接数据方面比内存中的Linq更有效(由于预先计算的索引、散列等),但在某些情况下,内存中的连接速度肯定会更快。但是,当您没有将所有数据都拉入内存时,通过连接获得的数据更少的好处可能会比连接中的任何性能改进产生更大的差异


所以没有一个明确的答案。从可行的方法开始,然后通过测量更改前后的时间来关注性能改进。

执行数据库查询的较慢部分之一是将数据从DBMS传输到本地进程。因此,限制传输到进程的数据量是明智的。仅传输实际计划使用的数据

因此,如果您查询“教师及其学生”,您将知道教师的ID将等于每个Student`中的外键'TeacherId
。那么,如果你已经知道外键的价值,为什么还要为老师的1000名学生中的每一位传输外键呢

让DBMS执行查询的另一个原因是数据库中的软件经过优化以执行查询。如果DBMS为一个查询创建了一个临时表,并且它检测到一个新查询需要相同的临时表,那么智能DBMS将重用这个临时表,即使查询来自另一个进程

智能DBMS将检测某些索引的使用频率高于其他索引,并将它们保存在内存中,而不是一直从磁盘读取它们

因此,DBMS有各种各样的技巧来加速查询的执行

您可以通过测量看到这些技巧的帮助:在一行中执行两次查询,并查看第二个查询的执行速度是否比第一个查询快。这种影响也是一个原因,您无法衡量让给定查询由DBMS执行还是在本地内存中执行更快。,正如一些人所建议的那样


唯一合适的方法是在较长的时间段内(如果不是几分钟,也可能是几小时),通过执行这些查询的大量进程,使用各种查询来衡量所选的策略。您可以肯定的是,执行可计算的查询不能从其他人执行的查询中获益。

执行数据库查询的较慢部分之一是将数据从DBMS传输到本地进程。因此,限制传输到进程的数据量是明智的。仅传输实际计划使用的数据

因此,如果您查询“教师及其学生”,您将知道教师的ID将等于每个
Student`中的外键'TeacherId
。那么,如果你已经知道外键的价值,为什么还要为老师的1000名学生中的每一位传输外键呢

让DBMS执行查询的另一个原因是数据库中的软件经过优化以执行查询。如果DBMS为一个查询创建了一个临时表,并且它检测到一个新查询需要相同的临时表,那么智能DBMS将重用这个临时表,即使查询来自另一个进程

智能DBMS将检测某些索引的使用频率高于其他索引,并将它们保存在内存中,而不是一直从磁盘读取它们

因此,DBMS有各种各样的技巧来加速查询的执行

您可以通过测量看到这些技巧的帮助:在一行中执行两次查询,并查看第二个查询的执行速度是否比第一个查询快。这种影响也是一个原因,您无法衡量让给定查询由DBMS执行还是在本地内存中执行更快。,正如一些人所建议的那样


唯一合适的方法是在较长的时间段内(如果不是几分钟,也可能是几小时),通过执行这些查询的大量进程,使用各种查询来衡量所选的策略。您可以肯定的是,执行可计算的查询并不能从其他人执行的查询中获益。

测量“更快的执行时间”非常容易使用秒表测量执行时间。我认为使用
IQueryable
和表达式的概念更符合评估表达式树(或意图本身)并确定/优化它的思路。将其视为SQL查询优化程序,因为您提出了一个表达式树,并且该树被优化/缩减为更好的表达式。因此,这种方法范围表示法并不适用于此,因为它并不复杂。我目前的一般评论是“更好”/“最好”等:除非你定义它,否则在工程中没有“更好”/“最好”这样的东西。同样不幸的是,所有合理的实用定义都需要大量的经验和大量的因素