在內(nèi)存數(shù)據(jù)庫中提高吞吐量的唯一方式就是減少執(zhí)行指令數(shù)目。
大多代碼都是為了人能理解而不是單為了性能。
接下來從邏輯查詢方面進(jìn)行分析。
看下面的例子

根據(jù)這個(gè)例子可以得到一個(gè)查詢樹和查詢計(jì)劃。

這里的查詢語句被優(yōu)化器進(jìn)行重寫,重寫成Join。查詢樹和查詢計(jì)劃很好理解,但是對(duì)于CPU而言很不友好,過多的結(jié)構(gòu)和分支,無論for還是if都會(huì)產(chǎn)生大量的分支,導(dǎo)致CPU要不斷刷新管道和緩存;大量的函數(shù)調(diào)用導(dǎo)致CPU在內(nèi)存總不斷跳躍。

在執(zhí)行B.val = ? +1時(shí),有參數(shù)輸出,執(zhí)行這一條語句需要傳入?yún)?shù)、當(dāng)前元組、當(dāng)前元組所在表的格式,需要大量的函數(shù)調(diào)用,代價(jià)很大。
Code Specialization
一個(gè) 解決方式就是code specialization,產(chǎn)生專門針對(duì)DBMS task的代碼來較少指令數(shù)量。
對(duì)于上面的操作而言,都是一些通用的查詢編譯過程,支持大多數(shù)查詢。但是如果是不同的輸入具有相似的執(zhí)行模式,可以在本地編譯任何數(shù)據(jù)庫的CPU密集型實(shí)體,即對(duì)一些特殊的查詢進(jìn)行特定的編譯設(shè)計(jì)。
訪問方法
存儲(chǔ)過程
操作員執(zhí)行
謂詞評(píng)估
記錄操作
這樣做的好處是
- 屬性類型是先驗(yàn)已知的。
數(shù)據(jù)訪問函數(shù)調(diào)用可以轉(zhuǎn)換為內(nèi)聯(lián)指針轉(zhuǎn)換。
即,可以直接通過offset訪問元組中的某個(gè)屬性。 - 謂詞是先驗(yàn)已知的。
可以使用原始數(shù)據(jù)直接比較來評(píng)估它們。 - 循環(huán)中沒有函數(shù)調(diào)用
允許編譯器高效地將數(shù)據(jù)分發(fā)到寄存器并增加緩存重用。
因?yàn)闆]有函數(shù)調(diào)用,所以只需要直接比較內(nèi)存塊的幾個(gè)offset的某個(gè)size的數(shù)據(jù)的關(guān)系即可。
Code Generation 代碼生成
兩種方法
移植
把關(guān)系查詢計(jì)劃轉(zhuǎn)化為命令語言源碼(C/C++),然后再用傳統(tǒng)編譯器來產(chǎn)生本地碼JIT編譯(LLVM)
生成可快速編譯為本地碼的查詢的中間表示(IR)
HIQUE - Code Generation
對(duì)于一個(gè)給定的查詢計(jì)劃,產(chǎn)生一個(gè)C/C++程序來實(shí)現(xiàn)查詢的執(zhí)行(將所有的謂詞和類型轉(zhuǎn)換都固定下來)。用線程的編譯器把代碼轉(zhuǎn)化為一個(gè)共享的對(duì)象,將起鏈接到DBMS的進(jìn)程中(類似于C++寫的python庫),然后調(diào)用exec函數(shù)(在一個(gè)進(jìn)程中啟動(dòng)另一個(gè)程序執(zhí)行的方法)
對(duì)于查詢計(jì)劃的特定部分,通過算法將這部分進(jìn)行重新編譯,并連接到最終的查詢程序中。
生成的查詢代碼的組件可以調(diào)用DBMS中任何其他函數(shù),這允許它使用與Interpreted Plan相同的組件:并發(fā)控制、檢查點(diǎn)、索引等。
Interpreted Plan 與 Templated Plan
- 需要明確表中的信息,如,屬性值大小等。
- 計(jì)算每個(gè)tuple的大小
- 返回tuple指針
比如對(duì)于
Select * from A where A.val=?+1

在解釋的計(jì)劃中, 其中g(shù)et_tuple首先要獲取從目錄中獲取表的格式,根據(jù)元組大小計(jì)算偏移量,然后返回元組的指針;eval()是遍歷謂詞樹獲取值,再獲取目標(biāo)屬性的偏移量,根據(jù)需要進(jìn)行比較操作,返回true/false。
而對(duì)于模板化的計(jì)劃,已經(jīng)定義好了像前面解釋的計(jì)劃中的獲取表的格式、元組大小這些信息,按照模板執(zhí)行就行了。
對(duì)查詢編譯性能的評(píng)估
- Generic Iterators:通用模型
- Optimized Iterators:對(duì)屬性值有特定代碼生成的模型,即,固定屬性值,固定屬性值大小
- Generic Hardcoded:對(duì)謂詞和泛型迭代器產(chǎn)生特定的代碼
- Optimized Hardcoded:直接訪問元組的評(píng)估模型
- HIQUE:對(duì)特定查詢計(jì)劃產(chǎn)生代碼的評(píng)估模型
JIT編譯(LLVM)
關(guān)系型操作是對(duì)查詢有效的方式,但不是執(zhí)行查詢最有效率的方式。需要長時(shí)間進(jìn)行編譯C/C++ 源代碼 成 可執(zhí)行代碼;HIQUE不支持完全的管道,它的管道會(huì)因?yàn)槠渌麛?shù)據(jù)沒有處理完而等待其他數(shù)據(jù)。

Hyper數(shù)據(jù)庫實(shí)現(xiàn)了JIT,用LLVM編譯器去編譯上面的查詢計(jì)劃,盡可能的將元組留存在CPU的寄存器中。核心部件是低級(jí)編程語言IR,不是所有的DBMS都需要用IR實(shí)現(xiàn),LLVM可以調(diào)用C++。
它會(huì)根據(jù)管道瓶頸生成代碼,但是多個(gè)core或者多個(gè)thread都不能同時(shí)在一個(gè)查詢中的多個(gè)管道上運(yùn)行,只能一個(gè)線程按順序在多個(gè)管道上完成處理。但是可以安排在管道執(zhí)行的先后順序。