CMU Database Systems - Sorting,Aggregation,Join
Sorting
排序如果可在內(nèi)存里面排,用經(jīng)典的排序算法就ok,比如快排
問題在于,數(shù)據(jù)表中的的數(shù)據(jù)是很多的,沒法一下都放到內(nèi)存里面進(jìn)行排序
所以就需要用到,外排,多路并歸排序
看下最簡(jiǎn)單的,2路并歸排序,
設(shè)文件分為N個(gè)page,memory中一次最多可以放入B個(gè)pages
所以在sort過程,一次性可以載入B個(gè)page,在內(nèi)存中page內(nèi)排序,寫回disk,稱為一輪,run
那么如果一共N個(gè)page,需要N/B+1個(gè)run
在merge過程,如果雙路并歸排序,只需要用到3個(gè)page的buffer,多了也沒用
Merge過程的cost
每個(gè)pass都需要讀寫一遍所有的數(shù)據(jù),cost為2N
2 way,所以一共有1 + logN個(gè)pass
多路并歸排序的通用公式如下,
其他都比較容易理解,為什么way數(shù)是B-1?
因?yàn)閙emory一共B個(gè)buffer,需要留一個(gè)output,剩下的用于merge,所以最多是B-1路并歸排序
?
如果我們有B+ index的情況下,
分兩種情況,要排序的字段有Clustered B+索引,那么直接從左到右遍歷葉子節(jié)點(diǎn)就好
排序的字段不是Clustered B+索引,比如是secondary 索引
那么從索引里面只能獲取到排好序的id,然后要通過id去Clustered B+索引中取真正的value,效率也很低,每個(gè)record都需要一次io
?
Aggregation
Aggregation有兩種思路,
一種先排序sorting,然后再按順序做aggregate
這個(gè)方法明顯的問題,就是比較費(fèi),有些場(chǎng)景不需要sort,比如group by,distinct
所以第二種思路是Hashing,
在memory里面臨時(shí)維護(hù)一個(gè)hash table,去重或聚合都在hash table上完成
問題就是,如果hash table太大,內(nèi)存放不下怎么辦?
所以解法的思路,放不下,就切開,切成能放下的一個(gè)個(gè)partition,并且要保證一個(gè)key的數(shù)據(jù)都在一個(gè)partition里面,這樣只要保證內(nèi)存能夠放下一個(gè)partition就可以aggregate,不需要去讀其他的partition
第一次partition劃分成幾個(gè)partition,如果內(nèi)存B個(gè)buffer,劃分成B-1個(gè)partition;如果劃分完了某個(gè)partition還是放不下怎么辦,那就繼續(xù)劃分,直到所有partition都可以放到內(nèi)存中
這里有幾個(gè)問題,
首先,一個(gè)partition應(yīng)該不止一個(gè)key,如果只有一個(gè),第二步里面的h2感覺沒用
第二,假設(shè)數(shù)據(jù)是均勻分布的,不會(huì)出現(xiàn)太大的傾斜,不會(huì)有partition overflow
?
Join
為什么需要join?
因?yàn)椴煌臄?shù)據(jù)存在不同的表里面,所以要查詢就需要關(guān)聯(lián)
那么為什么不能放在一張表里面,關(guān)系表的設(shè)計(jì)有范式的要求,避免大量的數(shù)據(jù)重復(fù)
?
Join Operator Output
直接輸出data,這樣好處是,后續(xù)operator不用回到數(shù)據(jù)表再去讀數(shù)據(jù)
這個(gè)方法比較實(shí)用于TP需求,結(jié)果數(shù)據(jù)較少的情況
僅僅輸出ids,適合AP需求,join結(jié)果集非常大的情況
尤其適用于列存,因?yàn)檫@樣你只需要讀出join id列,也不浪費(fèi)
然后在最后要顯示的時(shí)候,才去把需要的數(shù)據(jù)從表里面查出來,這叫做late materialization
這樣的好處,過程中可能還有其他的join,過濾等,所以開始讀可能浪費(fèi),到最后真正需要的時(shí)候再讀
?
Join Cost
如何去評(píng)價(jià)join算法的好壞,就是要評(píng)價(jià)cost
傳統(tǒng)的數(shù)據(jù)庫的瓶頸在disk IO,所以這里就以磁盤IO的次數(shù)來評(píng)價(jià)join算法的好壞,這個(gè)和為何使用B+tree作為index的理由一樣
所以就是讀寫page的個(gè)數(shù)
?
Join算法?
Nested Loop Join
Simple,直覺的方式就是遍歷兩個(gè)表
這里的概念,分為Outer和Inner表
從Cost上看,最要取決于Outer的tuples數(shù),所以如果把較小的表N作為Outer會(huì)效率高些
比較明顯的問題是,沒有必要讀那么多遍的inner表
如果我能把outer表直接放在內(nèi)存中,那么只需要讀一遍inner就可以了,如果不行就用如下的block的方式
如果內(nèi)存大小是B,那么要用兩塊來放inner和output,所以可以用B-2來放outer
Cost,outer表M需要讀一次,inner表需要讀M/(B-2)次
這里也寫了,如果memory比較大,那么cost就是M+N,只需要讀一遍inner
?
如果有index,是否可以加快join的效率?應(yīng)該可以,但是效果要看是什么index,如果hash,C=O(1),B+tree,C=O(logn)
?
Sort-Merge Join?
這個(gè)方法要求,兩個(gè)表先排序,然后做一輪幷歸就可以完成join
所以這個(gè)方法適用于,兩個(gè)表本身就有序,或是在join key上有index
這個(gè)方法附帶的好處是結(jié)果有序
這個(gè)算法的Cost,主要是兩個(gè)表排序的cost,幷歸的cost就是M+N
?
Hash Join
HashJoin分為兩步,兩步的hash函數(shù)用同一個(gè)
Build,對(duì)較小的表建臨時(shí)的hash table
Probe,讀取另一張表,進(jìn)行join
這有個(gè)類似的問題,Hash Table里面存什么?
當(dāng)然可以直接存join的結(jié)果,也可以存tuple id,這個(gè)選擇就取決于場(chǎng)景
?
自然有個(gè)疑問,如果內(nèi)存放不下這個(gè)hash table怎么辦?
既然放不下,就需要分而治之,兩個(gè)表用相同的hash函數(shù),hash到相同數(shù)目的buckets里面去
在內(nèi)存中,一次只讀一組bucket來進(jìn)行join,是不是很ok
?
?那么如果hash成bucket的時(shí)候,不均衡,一個(gè)bucket也overflow,怎么辦?答案是繼續(xù)分
?
Grace Hash Join的cost
?
?所有join算法的Cost對(duì)比,
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/fxjwind/p/10906161.html
總結(jié)
以上是生活随笔為你收集整理的CMU Database Systems - Sorting,Aggregation,Join的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 宝可梦传说阿尔宙斯头目能抓吗?
- 下一篇: 统计单词个数