一尘不染

LINQ加入-表现

sql

我很好奇LINQ(不是LINQ to SQL)在后台执行的连接与Sql Server执行连接的方式究竟有何不同。

SqlServer在执行查询之前,会生成一个执行计划。执行计划基本上是一个表达式树,它认为这是执行查询的最佳方法。每个节点都提供有关是否执行排序,扫描,选择,合并等信息。

在执行计划的“加入”节点上,我们可以看到三种可能的算法:哈希联接,合并联接和嵌套循环联接。Sql
Server将根据内部表和外部表中的预期行数,我们正在执行的联接类型(某些算法不支持所有联接类型),是否需要对数据排序来为每个联接操作选择哪种算法。可能还有许多其他因素。

联接算法:

嵌套循环连接:最适合小输入,可通过有序内部表进行优化。

合并联接:最适合大中型输入,已排序的输入或需要订购的输出。

哈希联接:最适合大中型输入,可以并行化以线性扩展。

LINQ查询:

DataTable  firstTable, secondTable;

...

var rows = from firstRow in firstTable.AsEnumerable ()
                join secondRow in secondTable.AsEnumerable ()
                    on firstRow.Field<object> (randomObject.Property)
                    equals secondRow.Field<object> (randomObject.Property)
           select new {firstRow, secondRow};

SQL查询:

SELECT *
FROM firstTable fT
    INNER JOIN secondTable sT ON fT.Property = sT.Property

如果Sql
Server知道每个表中的行数很少,则可以使用嵌套循环联接;如果知道表中的一个表具有索引,则可以使用合并联接;如果知道每个表中都有很多行,则可以使用Hash联接。表,并且都没有索引。

Linq是否选择其加入算法?还是总是使用一个?


阅读 121

收藏
2021-03-10

共1个答案

一尘不染

Linq to SQL不会将连接提示发送到服务器。因此,使用Linq to SQL的联接的性能将与“直接”发送到服务器(即使用纯ADO或SQL Server
Management Studio)的同一联接的性能相同,而没有指定任何提示。

Linq to SQL也 不允许
您使用联接提示(据我所知)。因此,如果要强制执行特定类型的联接,则必须使用存储过程或Execute[Command|Query]方法来执行。但是,除非您通过编写来指定INNER [HASH|LOOP|MERGE] JOIN联接类型,否则SQL Server始终会选择它认为最有效的联接类型-查询的来源无关紧要。

其他Linq查询提供程序(例如Entity Framework和NHibernate Linq)将执行与Linq to
SQL完全相同的操作。这些都没有直接了解如何为数据库建立索引的知识,因此它们都没有发送连接提示。

Linq to Objects有点不同-在SQL Server中,它将(几乎?)始终执行“哈希联接”。这是因为它缺少执行合并联接所需的索引,并且哈希联接
通常
比嵌套循环更有效,除非元素的数量很小。但是首先确定一个元素中的元素数量IEnumerable<T>可能需要完整的迭代,因此在大多数情况下,假设最坏的情况并使用哈希算法会更快。

2021-03-10