哈希键探测和残差

The*_*war 21 performance sql-server execution-plan database-internals query-performance

比如说,我们有一个这样的查询:

select a.*,b.*
from 
a join b
on a.col1=b.col1
and len(a.col1)=10
Run Code Online (Sandbox Code Playgroud)

假设上述查询使用 Hash Join 并具有残差,则探测键将为col1,残差将为len(a.col1)=10

但是在查看另一个示例时,我可以看到探针和残差是同一列。以下是对我想说的内容的详细说明:

询问:

select *
from T1 join T2 on T1.a = T2.a 
Run Code Online (Sandbox Code Playgroud)

执行计划,突出显示探测和残差:

在此处输入图片说明

测试数据:

create table T1 (a int, b int, x char(200))
create table T2 (a int, b int, x char(200))

set nocount on
declare @i int
set @i = 0
while @i < 1000
  begin
      insert T1 values (@i * 2, @i * 5, @i)
    set @i = @i + 1
  end

declare @i int
set @i = 0
while @i < 10000
  begin
    insert T2 values (@i * 3, @i * 7, @i)
    set @i = @i + 1
  end
Run Code Online (Sandbox Code Playgroud)

题:

探针和残差如何成为同一列?为什么SQL Server 不能只使用probe 列?为什么它必须使用与残差相同的列来再次过滤行?

测试数据参考:

Pau*_*ite 22

如果联接在一个类型为tinyintsmallintinteger* 的列上,并且如果两列都被约束为NOT NULL,则散列函数是“完美的”——意味着没有散列冲突的机会,并且查询处理器不必检查值再次确保它们真正匹配。

否则,您将看到残差,因为哈希桶中的项目被测试是否匹配,而不仅仅是哈希函数匹配。

您的测试未指定NULLNOT NULL列(顺便说一句,这是一种不好的做法),因此您似乎正在使用NULL默认数据库。

更多信息,请参阅 Dmitry Pilugin 的文章Join Performance、Implicit Conversions, and Residuals and Hash Join Execution Internals


* 其他符合条件的类型是bitsmalldatetimesmallmoney(var)char(n) for n = 1 和二进制排序规则