如何识别执行计划将考虑嵌套循环连接或散列连接算法?

时间:2016-08-25 18:11:48

标签: sql-server join

我想知道是否有任何特定的数据模式/算法用于决定是否进行嵌套循环连接或散列匹配连接。如果两个输入都在具有相同记录数的连接列上排序,则可以选择Merge Join,但是任何人都可以解释其他两个?

2 个答案:

答案 0 :(得分:0)

一般而言,当连接的两侧相对较小(与基数对话)或当一侧较小而另一侧的访问路径有效(即,它被索引)时,选择嵌套循环。这里的一个例子是我有一个“类型”表(例如一个有效状态代码表)和另一个表,它将这些类型之一作为其一个列的值。为了充实这一点,请考虑以下因素:

create table dbo.OrderStatusCode (
   OrderStatusCodeID tinyint not null,
      constraint [PK_OrderStatusCode] primary key clustered (OrderStatusCodeID),
   Name varchar(255) not null
);

insert into dbo.OrderStatusCode (OrderStatusCodeID, Name)
values 
    (1, 'New'),
    (2, 'Open'),
    (3, 'In Process'),
    (4, 'Shipped'),
    (5, 'Closed'),
    (6, 'Returned');

create table dbo.Orders (
   OrderID int identity not null,
      constraint [PK_Orders] primary key clustered (OrderID),
   OrderStatusCodeID tinyint not null,
      constraint [FK_Orders_OrderStatusCode] foreign key
      (OrderStatusCodeID) references dbo.OrderStatusCode(OrderStatusCodeID)
   --«other stuff for the order table»
);

create index [IX_Orders__OrderStatusCodeID] on dbo.Orders (OrderStatusCodeID);

select o.*
from dbo.Orders as o
join dbo.OrderStatusCode as osc
    on o.OrderStatusCodeID = osc.OrderStatusCodeID
where osc.Name in ('New', 'Open', 'In Process');

据推测,Order记录的数量远远超过OrderStatusCode记录的数量。此外,由于Orders.OrderStatusCode上的非聚集索引,该列的访问在该表中是有效的。因此,这里可以使用嵌套循环来执行以下操作(在伪代码中):

  • 对于每个状态代码(“新”,“打开”,“正在处理”)
    • 获取与该状态代码相关联的OrderStatusCodeID
    • 在订单上使用[IX_Orders__OrderStatusCodeID]索引查找具有该OrderStatusCodeID的行

相比之下,哈希匹配在某种程度上是最后的手段,因为它是三种连接算法中最昂贵的(一般来说)。也就是说,您没有嵌套循环或合并连接算法的条件。在以下情况中可以看到:     - 连接的任何一方都不小     - 就查找与连接谓词匹配的行的容易程度而言,连接的一侧或两侧效率低下

请注意,在所有情况下,这些决策都是由优化程序根据统计信息做出的。如果您的统计信息未准确反映基础数据,则优化程序可能会做出错误选择并为您的数据选择不适当的连接算法。 “相信,但要验证”!

答案 1 :(得分:-1)

有很多关于优化器如何选择this one等连接类型的文章。一些真正的细粒度细节可能会有所不同,具体取决于您正在谈论的SQL Server版本。