【连载】关系型数据库是如何工作的?(14) - 查询管理器之Nested Join

现在我们获取到了数据,让我们来关联它们吧。我会介绍3中常见你的关联方式:归并连接(Merge Join)、Hash连接(Hash Join)和嵌套循环连接(Nested Loop Join)。在这之前,我们需要介绍两个新概念:内关系和外关系,一个关系可能是:

  • 一张表
  • 一个索引
  • 一个中间结果

当你连接两个关系时,每种连接算法管理关系会有所不同。在文章的其余部分,我假设:

  • 外关系是指左边的数据集合
  • 内关系是指右边的数据集合

例如:A连接B,A就是外关系,B就是内关系。

大部分时候,A连接B和B连接A的成本是不一样的。在这一章,我会假设外关系有N个元素,内关系有M个元素。记住,实际上通过统计信息中就可以知道N和M。

嵌套循环连接(Nested loop join)

嵌套循环连接是最简单的一种连接。下边是其连接原理:

  • 遍历外关系的每一行;
  • 遍历内关系中的每一行,并比较是否合当前外关系行匹配。

下面是伪代码:

nested_loop_join(array outer, array inner)
  for each row a in outer
    for each row b in inner
      if (match_join_condition(a,b))
        write_result_in_output(a,b)
      end if
    end for
   end for

因为是一个两层遍历,所以其时间复杂度是O(N*M)。

从磁盘IO角度来看,外关系中N个元素每一次循环,都需要读取内关系中的M个元素,这样就需要从磁盘读取N+N*M次。如果内关系足够的小,就可以将内关系放入内存,这样实际只需要读取磁盘M+N次。上述情况,只有在内关系最小的情况下才可行,因为这样其更容易放入内存。

从时间复杂度来看,放入内存并无不同;但从磁盘IO会更好,因为其只需要读取一次内关系。当然,内关系也可以用索引来代替,这样其会有更好的磁盘IO性能。

这种算法非常简单,当内关系太大无法放入内存时会有一个变种,其相对会有更少的磁盘IO。下边是其思想:

  • 无须一行一行的读取两个关系数据;
  • 可以一组一组的读取,并且将其放入内存中;
  • 比较两组数据得到匹配的行;
  • 加载新的两组数据并比较;
  • 知道所有数据比较完成。

下边时一段伪代码:

// improved version to reduce the disk I/O.
nested_loop_join_v2(file outer, file inner)
  for each bunch ba in outer
  // ba is now in memory
    for each bunch bb in inner
        // bb is now in memory
        for each row a in ba
          for each row b in bb
            if (match_join_condition(a,b))
              write_result_in_output(a,b)
            end if
          end for
       end for
    end for
   end for

这个版本的算法时间复杂度没有任何变化,但是磁盘IO有所降低:

  • 之前的版本需要访问磁盘N+M*N次;
  • 这个新版本需要访问磁盘number_of_bunches_for(outer)+ number_of_ bunches_for(outer)* number_of_ bunches_for(inner)次;
  • 如果增加每组的元素数量,会降低磁盘的访问次数。

虽然这个版本算法每次磁盘访问会获取更多的数据比之前的算法,但其实没关系,因为它是顺序读取(顺序读取的关键时间是耗在读取第一份数据时)。


译者注:其实是一种拿空间换时间的思路,这种思路很常见,比如Java中的TreadLocal实现。这样做有两个大前提:
1. 空间成本比时间成本更加廉价。想想我们的存储介质是不是在不断的降价呢?想想CPU的价格是不是远远高于磁盘呢?
2. 顺序读取每组数据。因为如果是随机读取每组数据中的元素,那么磁头仍然需要不断的调整磁道,虽然看起来是一次读取一组数据,实际仍然相当于读取多次。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值