数据库连接算法分析

算法分类

  1. nested loop
  2. block nested loop
  3. one-pass
  4. tpmms
  5. 2-hash
  6. index join

MySQL的文档中提到了nested loop,block nested loop,index join,在8.0中新增了hash join。但是没有提到one-pass,tpmms

 

参考资料

http://www.mathcs.emory.edu/~cheung/Courses/554/Syllabus/4-query-exec/

http://www.cs.sjsu.edu/faculty/pollett/157b.12.05s/Lec16032005.pdf

https://dev.mysql.com/doc/refman/8.0/en/hash-joins.html

 

操作对象

表R和表S

B(R)和B(S)分别表示两个表的块数

可用内存大小为B(M)

 

nested loop

最简单的算法

for (r in R) {
    for (s in S) {
        if (s,r) match condition, output (s,r)
    }
}

IO消耗: B(R) * B(S)

内存限制:对内存要求不高,B(M) > = 2即可

 

如果是3个表,算法如下

for (r in R) {
    for (s in S) {
        for (t in T) {
            if (r,s,t) match condition, output (r,s,t);
        }    
    }
}

 

block nested loop

nested loop效率不高,因为没有将行数据缓存

block nested loop的思路是尽可能将一些数据缓存在内存,减少IO次数
 

do: load M-1 block data from R into M-1;
for (r in M-1) {
    for (s in S) {
        if (r,s) match condition, output (r,s)
    }
}
repeat;

IO消耗:B(R) / B(M-1) * B(S) + B(R)

对内存要求不高: B(M) >= 3

 

如果是3个表,算法如下:

do: load data from R into M-1;
    do: load from R into M-1
         if (M-1 is full) {
            for ( (r,s) in M-1) {
                for (t in T) {
                    if (r,s,t) match condition, output (r,s,t);
                }
            }
            empty(M-1)
         }
    }
    repeat;
}
repeat;

// 上面的操作结束后,如果M-1里还有数据
for ( (r,s) in M-1) {
     for (t in T) {
         if (r,s,t) match condition, output (r,s,t);
     }
}

 

one-pass

如果其中一个表的数据量较小,比内存小,可以使用效率更高的one-pass算法

将较小的表全部放入内存,构造一个搜索结构(比如hash)

load all R into M-1, construct a hashMap "H"

for (s_ in S) {
    search s_'s reference key in H, get r
    if (r, s_) match condition, output (r, s_); 
}

 

IO消耗(只考虑磁盘IO,内存操作可忽略):B(R) + B(S)。比block nested join好很多

内存限制:B(M) >= B(R) + 1,内存需要比R表大(假设R是R和S中较小的表)

 

tpmms, two-phase multi-way merge sort based join

R和S都较大,无法使用one-pass算法

phase 1:将R和S看成一段一段的,每段的大小都是M。依次将每段数据读入内存,排好序之后回写。

do: load M block data from R

sort these data, write back to R

repeat;



do: load M block data from S

sort these data, write back to S

repeat;

 

IO消耗:读写R,S各一次  =>  2 *(B(R) + B(S))

内存限制:暂无

 

phase 2:

从R和S的每一段中,都取一块数据,放入内存(因此R和S的总段数不能大于内存块数)

循环: 从R和S中的每一段都取一个block,放入内存;M(R)表示内存中R表的数据,M(S)表示内存中S表的数据

    从M(R)中取最小值r, M(S)中取最小值s;

    如果r < s, 查找下一个r;

    如果r > s, 查找下一个s;

    r,s相等, 输出r,s的连接结果;

    如果M(R)或M(S)中有一block全部查找过,则从该块来源的段中取下一块,替换该块。

循环:end

phase 2 分析:

IO消耗:读R,S = B(R) + B(S)

内存限制: R和S的总段数不能超过B(M) ,所以 B(R) + B(S) <= B(M)的平方

 

tpmms, 先排序版本

如果内存不足,连上面tpmms的内存要求都达不到,可以使用tpmms-先排序 算法。

伪代码如下:

phase1:

使用tpmms分别对R和S所有数据排序;

 phase1 分析:

IO消耗:2次读,2次写 =  4(B(R) + B(S))

内存限制: B(R) <= B(M)的平方

 

phase2: 

将R分成一段一段的,每段为M-1个块。

循环:从R中读取一段进内存;从S中读取一块进内存

    循环:读取内存中R的记录r和内存中S的记录s

        r < s, 读取下一个r;

        r>s,去读下一个s;

       r = s; 输出连接结果

    循环:end 

循环:end

IO消耗:B(R) + B(S)

内存限制: R中相同数量的r的最大数量不能超过B(M) - 1

总结:

IO消耗: 5 (B(R) + B(S)) 

 

2-hash 

伪代码:

phase1 :

将内存M的M-1块,每一块视为一个hash桶。设计一个总长度为B(M) - 1的hash算法。

分别对R和S做如下操作:

循环:读取R,S中的一块

      读取块中每一条记录,执行hash计算,将记录放入计算后的内存hash桶;

      如果桶满了,写回磁盘;

循环:end

将剩下没满的桶都写回磁盘。

phase1将R/S的数据组装成不连续的hash表。

phase1分析:

IO消耗:读,写R和S =  2(B (R) + B(S))

内存限制:无

 

phase 2: 

在one-pass的连接运算中,首先将整个S放入内存构建hash,然后遍历R;

参考one-pass算法,每次从S中取一个桶的数据,放入内存

循环:从S中取一个桶的所有数据放入内存

     用桶中每一条数据构造hash;

     从R中取相应hash key的数据,每次读取一块到内存,与hash中的数据做连接操作

循环:end

phase 2分析:

IO消耗:B(R) + B(S)

内存限制:S或R中最大的桶的数据量不能超过B(M)-1条数据;

因此,内存绝对不能小于:在最理想的状态下,每个桶的大小相等都是 B(S) / ( B(M) - 1 ), 在其他情况下,最大桶的大小只会比这个值大,不会比这个值小。 所以内存绝对不能小于 ( B(M) - 1 )的平方;

当然,即使满足“绝对不能小于”的内存,也不代表一定定满足 “S或R中最大的桶的数据量不能超过B(M)-1条数据”;

 

index join

假设 R 表 (x, y), S表(y, z), S表在y上有索引

for (r in R) {

    search r.y in S, get List data s[];

    for (s in s[]) {
        if (r, s) match condition, output (r,s)
    }
}

分析:

假设对于R中的每条记,S中等于与它对应的记录数有V条,则需要的IO是B(V);

总IO消耗为每条记录IO消耗的累加 = B(R) + T(R) * B(V)的平均值,T(R)表示T表的行数

理想情况:V等于1,则 IO消耗 = B(R) + T(R)

额外的IO:访问索引也可能需要IO,索引可以存在磁盘上(考虑索引是聚集的和非聚集的时候,IO消耗不同),这里暂且忽略

如果R的数据量较小,不管S的数据量有多大,index join的效率都很高

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值