排序若是可在内存里面排,用经典的排序算法就ok,好比快排算法
问题在于,数据表中的的数据是不少的,无法一下都放到内存里面进行排序数据库
因此就须要用到,外排,多路并归排序函数
看下最简单的,2路并归排序,oop
设文件分为N个page,memory中一次最多能够放入B个pagesui
因此在sort过程,一次性能够载入B个page,在内存中page内排序,写回disk,称为一轮,run
那么若是一共N个page,须要N/B+1个run设计
在merge过程,若是双路并归排序,只须要用到3个page的buffer,多了也没用3d
Merge过程的costblog
每一个pass都须要读写一遍全部的数据,cost为2N
2 way,因此一共有1 + logN个pass排序
多路并归排序的通用公式以下,索引
其余都比较容易理解,为何way数是B-1?
由于memory一共B个buffer,须要留一个output,剩下的用于merge,因此最可能是B-1路并归排序
若是咱们有B+ index的状况下,
分两种状况,要排序的字段有Clustered B+索引,那么直接从左到右遍历叶子节点就好
排序的字段不是Clustered B+索引,好比是secondary 索引
那么从索引里面只能获取到排好序的id,而后要经过id去Clustered B+索引中取真正的value,效率也很低,每一个record都须要一次io
Aggregation有两种思路,
一种先排序sorting,而后再按顺序作aggregate
这个方法明显的问题,就是比较费,有些场景不须要sort,好比group by,distinct
因此第二种思路是Hashing,
在memory里面临时维护一个hash table,去重或聚合都在hash table上完成
问题就是,若是hash table太大,内存放不下怎么办?
因此解法的思路,放不下,就切开,切成能放下的一个个partition,而且要保证一个key的数据都在一个partition里面,这样只要保证内存可以放下一个partition就能够aggregate,不须要去读其余的partition
这里有几个问题,
首先,一个partition应该不止一个key,若是只有一个,第二步里面的h2感受没用
第二,假设数据是均匀分布的,不会出现太大的倾斜,不会有partition overflow
为何须要join?
由于不一样的数据存在不一样的表里面,因此要查询就须要关联
那么为何不能放在一张表里面,关系表的设计有范式的要求,避免大量的数据重复
直接输出data,这样好处是,后续operator不用回到数据表再去读数据
这个方法比较实用于TP需求,结果数据较少的状况
仅仅输出ids,适合AP需求,join结果集很是大的状况
尤为适用于列存,由于这样你只须要读出join id列,也不浪费
而后在最后要显示的时候,才去把须要的数据从表里面查出来,这叫作late materialization
这样的好处,过程当中可能还有其余的join,过滤等,因此开始读可能浪费,到最后真正须要的时候再读
如何去评价join算法的好坏,就是要评价cost
传统的数据库的瓶颈在disk IO,因此这里就以磁盘IO的次数来评价join算法的好坏,这个和为什么使用B+tree做为index的理由同样
因此就是读写page的个数
Nested Loop Join
Simple,直觉的方式就是遍历两个表
这里的概念,分为Outer和Inner表
从Cost上看,最要取决于Outer的tuples数,因此若是把较小的表N做为Outer会效率高些
比较明显的问题是,没有必要读那么多遍的inner表
若是我能把outer表直接放在内存中,那么只须要读一遍inner就能够了,若是不行就用以下的block的方式
若是内存大小是B,那么要用两块来放inner和output,因此能够用B-2来放outer
Cost,outer表M须要读一次,inner表须要读M/(B-2)次
这里也写了,若是memory比较大,那么cost就是M+N,只须要读一遍inner
若是有index,是否能够加快join的效率?应该能够,可是效果要看是什么index,若是hash,C=O(1),B+tree,C=O(logn)
Sort-Merge Join
这个方法要求,两个表先排序,而后作一轮幷归就能够完成join
因此这个方法适用于,两个表自己就有序,或是在join key上有index
这个方法附带的好处是结果有序
这个算法的Cost,主要是两个表排序的cost,幷归的cost就是M+N
Hash Join
HashJoin分为两步,两步的hash函数用同一个
Build,对较小的表建临时的hash table
Probe,读取另外一张表,进行join
这有个相似的问题,Hash Table里面存什么?
固然能够直接存join的结果,也能够存tuple id,这个选择就取决于场景
天然有个疑问,若是内存放不下这个hash table怎么办?
既然放不下,就须要分而治之,两个表用相同的hash函数,hash到相同数目的buckets里面去
在内存中,一次只读一组bucket来进行join,是否是很ok
那么若是hash成bucket的时候,不均衡,一个bucket也overflow,怎么办?答案是继续分
Grace Hash Join的cost
全部join算法的Cost对比,