隨著數(shù)字化技術(shù)對各行各業(yè)的不斷滲透,人大金倉在金融、能源、電信等行業(yè)逐步進(jìn)入深水區(qū),面臨越來越多的核心類系統(tǒng)改造升級,這些系統(tǒng)不僅需要滿足在線交易系統(tǒng)運(yùn)行的高實(shí)時(shí)性要求,還需要保證高效分析能力以幫助客戶進(jìn)行業(yè)務(wù)決策。
數(shù)據(jù)庫中SQL表達(dá)式及PLSQL代碼實(shí)現(xiàn)的都是通用邏輯,這就導(dǎo)致在語句執(zhí)行過程中可能形成大量不必要的邏輯跳轉(zhuǎn)和代碼分支遍歷,進(jìn)而成倍甚至成指數(shù)級增加底層指令的執(zhí)行,造成CPU過高壓力。尤其在較為復(fù)雜分析類計(jì)算場景中,這種性能損耗尤其嚴(yán)重。
為了解決這種無效性能損耗,KES使用動(dòng)態(tài)編譯(Just-in-time compilation,JIT)技術(shù),將代碼扁平化執(zhí)行。簡單說就是通過直接調(diào)用對應(yīng)的函數(shù),并且在已知輸入情況下精簡代碼邏輯分支的方式,在復(fù)雜計(jì)算的分析場景下顯著降低CPU單位負(fù)載壓力,有效提高數(shù)據(jù)庫整體性能。
什么是JIT
在解釋JIT之前,我們先來了解下什么是編譯器:它是將高級語言源代碼翻譯成機(jī)器語言(或翻譯成比原始程序低級代碼)的程序。
從“代碼”到“代碼”的轉(zhuǎn)換:
轉(zhuǎn)換后的代碼:
-計(jì)算機(jī)可以直接執(zhí)行的機(jī)器語言(本機(jī)代碼);
-比原始程序低級的中間語言代碼。
在以前,程序通常有兩種編譯運(yùn)行方式 - 靜態(tài)編譯與動(dòng)態(tài)直譯,現(xiàn)如今又出現(xiàn)了即時(shí)編譯方式。
提前 (Ahead-of-Time: AOT) 編譯 - 即靜態(tài)編譯:在運(yùn)行應(yīng)用程序之前預(yù)編譯應(yīng)用程序的編譯。
典型代表:C
-將源代碼 (.c) 轉(zhuǎn)換為機(jī)器語言(本機(jī)代碼);
-建二進(jìn)制文件;
2、解釋器(interpreter)- 動(dòng)態(tài)直譯:執(zhí)行以編程語言編寫的源代碼或中間表達(dá)式并按順序解釋它們的程序。
典型代表:JAVA-JVM
-代碼“在解釋的同時(shí)執(zhí)行”;
-優(yōu)點(diǎn)是無需事先編譯,程序獨(dú)立于特定架構(gòu);
-缺點(diǎn)是運(yùn)行性能低。
3、即時(shí) (JIT) 編譯:在軟件執(zhí)行期間編譯代碼以提高執(zhí)行速度的編譯器;
JAVA
-在運(yùn)行時(shí)將頻繁執(zhí)行的方法編譯為機(jī)器代碼;
Python + Numba
-在運(yùn)行時(shí)編譯并運(yùn)行指定函數(shù)。
即時(shí) (JIT) 編譯融合了前二種編譯方式,一句一句編譯源代碼執(zhí)行,同時(shí)將編譯過的代碼緩存起來以降低性能損耗。相對于靜態(tài)編譯,即時(shí)編譯的代碼可以處理延遲綁定并增強(qiáng)安全性。簡單的說,JIT 是一種提高程序運(yùn)行效率的方法。
KES如何實(shí)現(xiàn)JIT
KES基于LLVM實(shí)現(xiàn)JIT特性。
KES把對應(yīng)的JIT 的提供者封裝成一個(gè)依賴庫,從而避免了JIT 對內(nèi)核代碼的侵入性。用戶可以按需開啟或關(guān)閉JIT功能;通過進(jìn)一步的抽象,KES還提供支持后期擴(kuò)展不同JIT的解決方案。其JIT實(shí)現(xiàn)過程概述如下:
1.表達(dá)式的中間表示(Exprstate)轉(zhuǎn)換為LVMM的中間表示(LVMM IR);
2.使用LVMM進(jìn)行JIT編譯,轉(zhuǎn)換為機(jī)器代碼;
3.KES執(zhí)行器將其做為內(nèi)部函數(shù)調(diào)用執(zhí)行;
KES基于JIT提供的優(yōu)化項(xiàng)
1、表達(dá)式計(jì)算優(yōu)化
針對WHERE 條件判斷、聚合運(yùn)算等場景實(shí)時(shí)將表達(dá)式的路徑編譯為具體代碼執(zhí)行,在此過程中大量的不必要的調(diào)用和分支跳轉(zhuǎn)會(huì)被優(yōu)化掉。
2、存取層優(yōu)化
數(shù)據(jù)庫執(zhí)行器通過存取層裝載數(shù)據(jù),針對特定的表結(jié)構(gòu),可以定制讀取和解析元組的代碼。如在解析元組的流程中,根據(jù)表結(jié)構(gòu)動(dòng)態(tài)生成的代碼,無需做數(shù)據(jù)類型的重復(fù)判斷,只按照順序解析數(shù)據(jù);以及在獲取部分列時(shí)實(shí)現(xiàn)直接根據(jù)對應(yīng)偏移量提取的數(shù)據(jù),跳過不需要提取的列,從而降低計(jì)算及I/O開銷。隨著處理的數(shù)據(jù)量的增加,節(jié)省的計(jì)算及I/O量將是驚人的。
3、執(zhí)行器流程優(yōu)化
LLVM中實(shí)現(xiàn)了對產(chǎn)生的中間表示代碼(IR)的優(yōu)化,這一定程度上也會(huì)提升數(shù)據(jù)庫查詢的執(zhí)行速度。從每一行數(shù)據(jù)的處理優(yōu)化提升到整條 SQL 的處理流程優(yōu)化:從傳統(tǒng)的相對低效的流水線執(zhí)行方式調(diào)整為循環(huán)批量處理方式,從而充分利用 CPU緩存,盡量避免去相對慢得多的內(nèi)存中存取數(shù)據(jù);再結(jié)合 CPU 向量計(jì)算相關(guān)指令集,進(jìn)一步提高性能。
JIT會(huì)提升CPU密集型查詢的性能,而對于短查詢的優(yōu)化有限,KES默認(rèn)開啟動(dòng)態(tài)編譯(JIT),運(yùn)行時(shí)會(huì)比較查詢的評估代價(jià)與JIT代價(jià)閥值的大小,判斷是否執(zhí)行JIT編譯。用戶也可以根據(jù)業(yè)務(wù)需要主動(dòng)設(shè)置JIT參數(shù)關(guān)閉動(dòng)態(tài)編譯。
JIT優(yōu)化性能實(shí)測
下面通過一個(gè)客戶業(yè)務(wù)分析場景的脫敏簡化版對比說明JIT對SQL執(zhí)行性能的提升:
EXPLAN ANALYZE結(jié)果:
總結(jié)展望
JIT可以幫助KES數(shù)據(jù)庫優(yōu)化SQL執(zhí)行邏輯,加快復(fù)雜SQL的查詢速度,從而提升KES整體性能。在TPC-H等數(shù)據(jù)庫測試中,KES的JIT編譯表達(dá)式執(zhí)行速度快了不止20%;在JIT模式下,創(chuàng)建索引的速度普遍可以提高5%-19%。
作為國內(nèi)成立最早、底蘊(yùn)最深的數(shù)據(jù)庫國家隊(duì),人大金倉始終以用戶為中心,致力于提供卓越的數(shù)據(jù)庫產(chǎn)品與服務(wù)。金倉人在廣泛關(guān)注及學(xué)習(xí)前沿技術(shù)的同時(shí),堅(jiān)持自主創(chuàng)新,不斷落地新理論,融合新技術(shù),以滿足日趨多元且極致的新需求,提升產(chǎn)品核心競爭力,持續(xù)為千行百業(yè)數(shù)字化轉(zhuǎn)型升級賦能。