多对一关系下TSQL Join内部实现及重复值连接效率问询
关于重复值连接的执行效率问题解答
嘿,这个问题问到点子上了,很多人都会好奇SQL Server在处理重复连接键的时候会不会做优化,我来给你详细拆解下~
核心问题:SQL Server会对每个重复的'Luke'都执行连接吗?
答案是:取决于执行计划选择的连接类型,默认情况下优化器不会主动先对左表(@tmp)去重再连接,但不同的连接策略会带来不同的执行逻辑:
1. 哈希连接(Hash Join)
这是小表连接时很常见的选择。SQL Server会先把右表(#test)的所有数据加载到内存,构建一个哈希表(以textval为键),然后遍历左表(@tmp)的每一行,用textval去哈希表中快速匹配。
- 不管@tmp里有多少个重复的'Luke',哈希表只会构建一次,所有重复值都是复用同一个哈希表做查找,不会重复读取#test,效率很高。
2. 嵌套循环连接(Nested Loops Join)
这种连接类型的行为分两种情况:
- 如果#test的
textval字段有索引:第一次处理'Luke'时,会通过索引查找匹配的行;后面的4个'Luke'会触发重绕(Rewinds)——也就是复用之前的查找结果,不需要再去#test里重新查询。这时候执行计划里的重绕次数会是4,重新绑定次数为0。 - 如果#test的
textval没有索引(就像你的例子里一样):每处理@tmp的一行,都要全表扫描一次#test,5个'Luke'就会扫5次#test,效率很低。
3. 合并连接(Merge Join)
如果两张表都按textval排序(或者有排序后的索引),优化器会选择合并连接。它会同时遍历两个表的排序结果,匹配相同的textval,重复的键会一次性处理,不会重复扫描#test。
怎么从执行计划里判断?
你提到执行计划里重绕/重新绑定次数为0,这大概率说明优化器选择了哈希连接或者合并连接:
- 哈希连接:查看运算符属性里的「构建次数」,应该是1,代表只构建了一次哈希表。
- 嵌套循环连接:如果重绕次数大于0,说明复用了之前的查询结果;如果重绕次数为0且没有索引,那就是每次都重复扫描右表了。
要不要手动优化?
如果你的@tmp数据量特别大,重复值很多,可以手动先去重再连接,比如:
WITH tmp_distinct AS ( SELECT DISTINCT textval FROM @tmp ) SELECT tmp.textval, t.ID FROM @tmp tmp LEFT JOIN tmp_distinct td ON tmp.textval = td.textval LEFT JOIN #test t ON td.textval = t.textval;
这样#test只需要和去重后的小数据集连接,再关联回原@tmp,能减少连接的总次数。但如果数据量不大,优化器的默认选择已经足够高效,不需要额外操作。
内容的提问来源于stack exchange,提问作者EvilDr
相关产品推荐
相关产品推荐

