【CMU15-445 Part-11】Join Algorithms

Part11-Join Algorithms

Why Do We Need to Join?

Join其实是关系数据库和范式化表时候所产生的副产物。

也就是说我们范式化表是为了减少冗余信息,而我们使用join就是为了去重建reconstruct 这些原本的tuple

Join Algorithms

主要关注两表的inner equijoin algorithms

通常,较小的表作为左表(left table / outer table)进行join,右表叫做inner table

Join Operators

在叶子节点处对表访问,将表中的tuple作为输入传给父节点的operator。

考虑1. output 查询计划生成树join算子之间传递的是什么 2. 如何判断算法的优劣------Cost Analysis Criteria

  1. 对于两个表R,S的tuple r,s进行join 级联操作,生成一个新的tuple,具体的内容取决于

    1. 查询处理模型 Query processing model (多个tuple)
    2. 存储模型 Storage model ,row / column 存
    3. 具体的query

    关于算子之间的输出传递,可以直接级联的结果进行传递,如果很多列则代价很大,可能进行一个预先的投影操作。还有就是only copy joins keys along with record ids.(特别针对列存) 叫做Late Materialization

  2. I/O Cost Analysis

    计算join过程必须使用的I/O次数来估计成本。只关心join操作的成本,不关心最后输出结果或者其他因素。

    M pages in table R m tuples in R
    N pages in table S n tuples in S

Join VS Cross-Product

cross-product 交叉连接

Join Algorithms

包括Nested Loop Join、Sort-Merge join、Hash Join

Nested Loop Join

cpp 复制代码
for each tuple r in R           // outer table
	for each tuple s in S:        // inner table
		 emit,if r and s match

stupid ! Cost: M + m* N 左表M个pages,然后m个tuple每次都扫描一次右表N个pages,代价就是M+m*N

优化:

  1. 小表作为左表

  2. Block Nested Loop Join

    使用block、page,可以多个tuple一个block/page,让outer table的一个block中所有tuple 完成和inner table中所有tuple的join,再去取下一个inner table的block。

    代价是:M+M*N,这里的话小表就是page少的了 不是tuple少的

  3. 对于outer table使用尽可能多的内存buffer来保存他,即B-2个block 来保存左表,1 block for inner table, 1 block for output result。

    Cost = M + [M / (B-2)] * N

    如果buffer够大可以放开左表,那cost = M+N

  1. 可以避免循序扫描通过使用index来找inner table matches

    1. 使用一个已经存在的index on inner table
    2. build one on the fly(hash table, B+ Tree) 针对join的index 叫做Spooling index. 查询结束删除index

    index不一定就是join on的key,也许join on col A and B,在A上有index也可以用索引探针(Index probe)来进行优化,先找A然后再匹配B列。

    假设C是index查找一个tuple的一个代价,Cost = M + m*C

  2. Sort-Merge Join

    1. 第一阶段---排序:sort both tables on the join keys;可以使用external merge sort或者内存中的快排
    2. 第二阶段---合并:使用游标对排好序的两个表的tuple进行逐个比较,匹配就输出。双指针。

    可能会需要backtracking 回溯操作,回到该值在inner table中第一次出现的地方。只会对inner table进行backtracking。

    Cost =

    最差的情况:outer table中的每个值和inner table中的每个值都相等,每个tuple m都得回溯一次,COST = M * N + SORT COST

    Sort-Merge join 用处:如果有一个或者俩表都on join key排好序了;或者要求order by,需要对结果排序。特别有个索引排好序 且是聚簇索引

  3. Hash Join

    1. hash function是确定的,两个表相同的key hash 结果相同。

    2. 基于hash key来讲outer table拆分成多个分区,付出前期成本来将数据拆分以此让查找或者探测过程更快。即value hash → partition i,R tuple must be in r_i,S tuple must be in s_i。因此R tuples in r_i只需要和S tuples in s_i 比较来进行join

    3. Basic Hash Join Algorithm

      1. Build:循序扫描outer relation 然后pop到hashtable 使用h_1

      2. Probe:对inner relation扫描,使用h_1 将每个tuple进行hash处理;会跳到相同的位置然后看有没有匹配的tuple。

      3. Key:是join操作基于的属性;Value:取决于上层算子的输入。

      4. Hash Table Values

        1. Full Tuple:避免回表IO,但是需要更多内存。
        2. Tuple Identifier:tuple标识符例如record id,适用于列存,
    4. Probe Phase Optimization:再build阶段创建一个bloom filter,在没有查看hash table的情况下可以通过它来判断要查找的tuple是否在这个hashtable中。也叫做sizeways information passing横向信息传递。

      1. Bloom Filter:是一种概率数据结构(Probabilistic DS)(bitmap)用来处理set membership查询(近似成员查询:该key在不在我的集合中)包括操作:insert(x),Lookup(x).好处是可能会假阳性,就是实际不在但是告诉你在,但是不会逻辑上影响正确性,不会假阴性就是在但是告诉你不在,这样就是逻辑错误了这种不会出现。
      2. 具体的优化是构建hash table的时候可能会溢出到磁盘,为key构建一个bloom filter,super small can fit in memory。避免潜在的无用的磁盘I/O
    5. Grace(partition) Hash Join:处理Hash Join don't fit in memory

      1. Build Phase:基于hash key将两张表拆分成多个分区,拆分成两个单独的hash table,outer table和inner table各自有一张hash table。
      2. Probe Phase:比较两张表对应分区的tuples,对匹配的分区进行nested-loop join。

      bucket chain hash table而非linear probe hash table。因为想要相同的数据hash到同一位置或者映射到同一分区。一一匹配去scan。

      都hash到一个bucket就会出问题,用递归分区Recursive Partitioning来解决。使用另外一个hash function h2来建立bucket_r,i。如果有足够buffer,且所有数据都能放在内存中,可以跨分区进行join操作,COST = 3 *(M+N)。分区的时候要对M outertable N innertable进行一轮读和一轮写,probe一轮

Observation

如果DBMS直到outer table的size可以去调整hash table或者buffer size,如果可以都内存就线性hash,如果需要溢出到磁盘就bucket。如果不知道size,可以使用动态hash table(linear extendable hash table)或者允许overflow pages,但是代价会很高。

  1. 什么情况下会不清楚outer table的size? 回答:多个操作之间所产生的临时中间表的size

除非排好序,否则hash join永远比其他join来的好

sorting适合于non-uniform data 或者结果需要排序的情况。

range join anti join?

相关推荐
指尖上跳动的旋律2 小时前
shell脚本定义特殊字符导致执行mysql文件错误的问题
数据库·mysql
一勺菠萝丶2 小时前
MongoDB 常用操作指南(Docker 环境下)
数据库·mongodb·docker
m0_748244832 小时前
StarRocks 排查单副本表
大数据·数据库·python
C++忠实粉丝3 小时前
Redis 介绍和安装
数据库·redis·缓存
wmd131643067123 小时前
将微信配置信息存到数据库并进行调用
数据库·微信
是阿建吖!3 小时前
【Linux】基础IO(磁盘文件)
linux·服务器·数据库
凡人的AI工具箱3 小时前
每天40分玩转Django:Django国际化
数据库·人工智能·后端·python·django·sqlite
ClouGence3 小时前
Redis 到 Redis 数据迁移同步
数据库·redis·缓存
m0_748236583 小时前
《Web 应用项目开发:从构思到上线的全过程》
服务器·前端·数据库
苏三说技术3 小时前
Redis 性能优化的18招
数据库·redis·性能优化