日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

怎样避免每次都解释大量指令?

發(fā)布時間:2024/9/3 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 怎样避免每次都解释大量指令? 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
簡介:向量化引擎為PolarDB-X的表達式計算帶來了顯著的性能提升。

作者:君啟




介紹


PolarDB-X是阿里巴巴自研的云原生分布式數(shù)據(jù)庫,采用了計算-存儲分離的架構(gòu),其中計算節(jié)點承擔著大量的表達式計算任務(wù)。這些表達式計算涉及到SQL執(zhí)行的各個環(huán)節(jié),對性能有著重要的影響。為此PolarDB-X引入向量化執(zhí)行引擎,為表達式計算帶來了幾十倍的性能提升。


傳統(tǒng)數(shù)據(jù)庫執(zhí)行器的缺陷


現(xiàn)代數(shù)據(jù)庫系統(tǒng)的執(zhí)行引擎,大多采用一次計算一行數(shù)據(jù)(Tuple-at-a-time)的處理方式,并且需要在運行時對數(shù)據(jù)類型進行解析和判斷,來適應(yīng)復雜的表達式結(jié)構(gòu)。我們稱之為“標量(scalar)表達式”。這種方式雖然易于實現(xiàn)、結(jié)構(gòu)清晰,但是當需要處理的數(shù)據(jù)量增大時,它具有顯著的缺陷:


為了適應(yīng)復雜的表達式結(jié)構(gòu),計算一條表達式往往需要引入大量的指令;對于行式執(zhí)行來說,處理單條數(shù)據(jù)需要算子樹重新進行指令解釋(instruction interpretation),從而帶來了大量的指令解釋開銷。據(jù)論文《MonetDB/X100: Hyper-Pipelining Query Execution》統(tǒng)計,在MySQL執(zhí)行TPC-H測試集的 Query1 時,指令解釋就耗費了90%的執(zhí)行時間。


此外,在最初的Volcano結(jié)構(gòu)設(shè)計中,算子內(nèi)部邏輯并沒有避免分支預測(branch prediction)。錯誤的分支預測需要CPU終止當前的流水線,將ELSE語句中的指令重新載入,我們將這一過程稱為pipeline flush或pipeline break。頻繁的分支預測錯誤會嚴重影響數(shù)據(jù)庫的執(zhí)行性能。


向量化執(zhí)行系統(tǒng)


數(shù)據(jù)庫向量化執(zhí)行系統(tǒng)最早由論文《MonetDB/X100: Hyper-Pipelining Query Execution》提出,它有以下幾個要點:

  • 采用vector-at-a-time的執(zhí)行模式,即以向量(vector)為數(shù)據(jù)組織單位。
  • 使用向量化原語(vectorization primitives)來作為向量化算子的基本單位,從而構(gòu)建整個向量化執(zhí)行系統(tǒng)。原語中避免產(chǎn)生分支預測。
  • 使用code generation(代碼生成)技術(shù)來解決靜態(tài)類型帶來的code explosion(代碼爆炸)問題。

  • 向量化引擎為PolarDB-X的表達式計算帶來了顯著的性能提升。在下圖中,橫軸為向量大小,縱軸為吞吐量,不同標量表達式和向量化表達式的性能測試對比結(jié)果如下:



    case表達式性能測試對比結(jié)果如下:





    整體流程


    PolarDB-X中,向量化表達式的執(zhí)行分為以下幾個階段:

  • 用戶SQL經(jīng)解析后,在validator中進行校驗,推導和修正表達式的類型信息;這一階段為向量化運算提供正確的、靜態(tài)的類型信息;
  • 在優(yōu)化器形成執(zhí)行計劃之后,需要對表達式樹進行表達式綁定,實例化對應(yīng)的向量化原語,同時分配好向量下標,供運行時內(nèi)存分配;
  • 執(zhí)行階段,依據(jù)Volcano式的結(jié)構(gòu),自頂向下的觸發(fā)執(zhí)行向量化原語,并將向量作為運行時數(shù)據(jù)結(jié)構(gòu)。



  • 運行時結(jié)構(gòu)


    數(shù)據(jù)結(jié)構(gòu)


    在PolarDB-X向量化執(zhí)行系統(tǒng)中,采用以下的數(shù)據(jù)結(jié)構(gòu)來存放數(shù)據(jù):



    向量化表達式執(zhí)行時,所有的數(shù)據(jù)都會存放在batch這一數(shù)據(jù)結(jié)構(gòu)中。batch由許多向量(vector)和一個selection數(shù)組而組成。其中,向量vector包括一個存儲特定類型的數(shù)值列表(values)和一個標識null值位置的null數(shù)組組成,它們在內(nèi)存中都是連續(xù)存儲的。null數(shù)組中的bit位以0和1來區(qū)分數(shù)值列表中的某個位置是否為空值。


    我們可以用vector(type, index)來標識batch中一個向量。每個向量有其特定的下標位置(index),來表示向量在batch中的順序;類型信息(type)來指定向量的類型。在進行向量化表達式求值之前,我們需要遍歷整個表達式樹,根據(jù)每個表達式的操作數(shù)和返回值來分配好下標位置,最后根據(jù)下標位置統(tǒng)一為向量分配內(nèi)存。


    延遲物化


    selection數(shù)組的設(shè)計體現(xiàn)了延遲物化的思想,參考論文《Materialization Strategies in a Column-Oriented DBMS》。所謂延遲物化,就是盡可能地將物化(matrialization)這一過程后推,減少內(nèi)存訪問帶來的開銷。在執(zhí)行表達式計算時,往往會先經(jīng)過Filter表達式過濾一部分數(shù)據(jù),再對過濾后的數(shù)據(jù)執(zhí)行求值處理;每次過濾都會影響到batch中所有的向量。以上圖中的batch為例,如果我們針對第0個向量設(shè)置 vector(int, 0) != 1這一過濾條件,假設(shè)vector(int, 0)中有90%的數(shù)據(jù)滿足該過濾條件(選擇率selectivity = 0.9),那么我們需要將batch中所有向量90%的數(shù)據(jù)重新物化到另一塊內(nèi)存中。而如果我們只記錄滿足該過濾條件的位置,存入selection數(shù)組,我們就可以避免這一物化過程。相應(yīng)的,以后每次向量化求值過程中,都需要參考此selection數(shù)組。


    向量化原語


    向量化原語是向量化執(zhí)行系統(tǒng)中的執(zhí)行單位,它最大程度限制了執(zhí)行期間的自由度。原語不用關(guān)注上下文信息,也不用在運行時進行類型解析和函數(shù)調(diào)用,只需要關(guān)注傳入的向量即可。它是類型特定(Type-Specific)的,即一類原語只能處理特定類型。


    向量化原語的主體是Tight-Loop的代碼結(jié)構(gòu)。在一個循環(huán)體內(nèi)部,只需要進行取值和運算即可,沒有任何的分支運算和函數(shù)調(diào)用。一個簡單的向量化原語結(jié)構(gòu)如下所示:


    map_plus_double_col_double_col(int n, double*__restrict__ res, double*__restrict__ vector1, double*__restrict__ vector2, int*__restrict__ selection) { if (selection) { for(int j=0;j<n; j++) { int i = selection[j]; res[i] = vector1[i] + vector2[i]; } } else { for(int i=0;i<n; i++) res[i] = vector1[i] + vector2[i]; } }

    注:*左右滑動閱覽


    其運算過程利用了selection數(shù)組,逐步對向量進行取值、運算和存值,如下圖所示:



    向量化原語帶來了以下優(yōu)點:

  • Type-Specific以及Tight-Loop的結(jié)構(gòu),大大減少了指令解釋的開銷;
  • 避免分支預測失敗和虛函數(shù)調(diào)用對CPU流水線的干擾,同時也能有利于 loop pipeline 優(yōu)化【論文引用】
  • 從向量中存取數(shù)據(jù),有利于觸發(fā)cache prefetch,減少cache miss帶來的開銷。

  • 我們?yōu)楦鞣N標量化表達式提供相應(yīng)的原語實現(xiàn),從而完成從標量到向量化的轉(zhuǎn)變。例如將加法運算 plus(Object, Object) 針對不同操作數(shù)類型生成原語,包括plus(double,double),plus(long, long)等。


    短路求值


    在向量化原語的基礎(chǔ)上,我們可以進一步對分支運算(也稱為控制流運算 Control-Flow)進行短路求值(short-circuit calculation)優(yōu)化,提升表達式計算的性能。


    例如,case 表達式由n個when表達式、n-1個then表達式、1個else表達式構(gòu)成。對于表達式


    select case when a > 1 then a * 2 when b > 1 then b * 2 else a * b


    其邏輯語義是:

    • 對于滿足 a > 1 的向量位置,計算 a * 2;
    • 對于滿足 a <= 1 and b > 1 的向量位置,計算 b * 2;
    • 對于滿足 a <= 1 and b <= 1 的向量位置,計算 a * b;
    • 把所有位置的數(shù)值組合在一起形成新的向量,輸出。


    具有以下樹形結(jié)構(gòu):



    由于標量化表達式按照volcano結(jié)構(gòu)編排,并提供了統(tǒng)一的next()的接口,case表達式必須執(zhí)行完所有的子表達式a>1,a*2,b>1,b*2和a*b之后,將全部結(jié)果匯總到一起,最后做case語義處理。這種執(zhí)行方式不能根據(jù)when表達式的處理結(jié)果及時終止計算過程,而是對全部子表達式無差別執(zhí)行。


    引入向量化執(zhí)行器以后,我們可以設(shè)計短路求值來優(yōu)化此問題,每一個子表達式需要被提供合適的selection數(shù)組,從而正確選擇列中合適的位置來進行向量運算。設(shè)第i個when條件表達式接受的selection元素集合為 ,其輸出的selection元素集合為,也就是第i個then條件表達式接受的selection元素集合。那么滿足?,其中是原始的selection數(shù)組中的下標集合。我們把求取selection元素集合的步驟稱為substract selection,case運算的整個過程如下圖所示:




    總結(jié)


    PolarDB-X向量化引擎利用原語(primitive)來構(gòu)建表達式,以向量作為運行時數(shù)據(jù)結(jié)構(gòu)。每種原語僅為特定類型進行服務(wù),從而減少了指令總數(shù);原語中的tight-loop結(jié)構(gòu)不僅對CPU流水線十分友好,也允許CPU進行數(shù)據(jù)預取,并且避免分支預測。此外,一些優(yōu)化如延遲物化、短路求值,進一步提升了表達式求值性能。


    然而,從用戶SQL到向量化執(zhí)行之間,存在著一道巨大的鴻溝。我們需要解決以下幾個重要問題:


    1. 如何確定表達式的輸入輸出類型,并為SQL中的表達式分配合適的原語?2. 每個原語需要使用不同的向量來進行輸入和輸出,如何為正確地為原語分配向量?3. 每種原語僅為特定類型進行服務(wù),那么我們必然需要為一個表達式配備大量不同的原語,來適應(yīng)不同的數(shù)據(jù)類型。如何應(yīng)對原語數(shù)量爆炸這一問題?


    在下一篇文章中,我們將為上述問題的解決方案進行詳細介紹。




    【相關(guān)閱讀】

    PolarDB-X 面向 HTAP 的混合執(zhí)行器

    PolarDB-X 面向 HTAP 的 CBO 優(yōu)化器

    如寶馬3系和5系:PolarDB-X 與 DRDS 并駕齊驅(qū)

    PolarDB-X 存儲架構(gòu)之“基于Paxos的最佳生產(chǎn)實踐”

    PolarDB-X 私有協(xié)議:提升集群的性能和穩(wěn)定性

    技術(shù)解讀 | PolarDB-X 分布式事務(wù)的實現(xiàn)

    技術(shù)解讀 | PolarDB-X 強一致分布式事務(wù)

    PolarDB-X 一致性共識協(xié)議 (X-Paxos)

    原文鏈接:https://developer.aliyun.com/article/782166?

    版權(quán)聲明:本文內(nèi)容由阿里云實名注冊用戶自發(fā)貢獻,版權(quán)歸原作者所有,阿里云開發(fā)者社區(qū)不擁有其著作權(quán),亦不承擔相應(yīng)法律責任。具體規(guī)則請查看《阿里云開發(fā)者社區(qū)用戶服務(wù)協(xié)議》和《阿里云開發(fā)者社區(qū)知識產(chǎn)權(quán)保護指引》。如果您發(fā)現(xiàn)本社區(qū)中有涉嫌抄襲的內(nèi)容,填寫侵權(quán)投訴表單進行舉報,一經(jīng)查實,本社區(qū)將立刻刪除涉嫌侵權(quán)內(nèi)容。

    總結(jié)

    以上是生活随笔為你收集整理的怎样避免每次都解释大量指令?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。