溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

PostgreSQL如何實現(xiàn)并行查詢

發(fā)布時間:2021-11-26 09:19:45 來源:億速云 閱讀:901 作者:小新 欄目:云計算

小編給大家分享一下PostgreSQL如何實現(xiàn)并行查詢,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

并行查詢的背景

隨著SSD等磁盤技術(shù)的平民化,以及動輒上百GB內(nèi)存的普及,I/O層面的性能問題得到了有效緩解。提升數(shù)據(jù)庫的擴展性能,可以追求Scale Out的方式,增加機器,往分布式方向發(fā)展,也可以追求Scale Up,增加硬件組件,充分利用各個硬件的資源,把單機的性能發(fā)揮到最大效果。相較而言,Scale Up通過軟件加速性能,依賴軟件層面的優(yōu)化,是低成本的擴展方案。

現(xiàn)代服務(wù)器除了磁盤和內(nèi)存資源的增強,多CPU的配置也足夠強大。數(shù)據(jù)庫的Join、聚合等操作內(nèi)存耗費比較大,很多時間花在了數(shù)據(jù)的交換和緩存上,CPU的利用率并不高,所以面向CPU的加速策略中,并發(fā)執(zhí)行是一種常見的方法。

查詢的性能是評價OLAP型數(shù)據(jù)庫產(chǎn)品好壞的核心指標,而并行查詢可以聚焦在數(shù)據(jù)的讀和計算上,通過把Join、聚合、排序等操作分解成多個操作實現(xiàn)并行。

并行查詢的挑戰(zhàn)在于,為了要做并行而加入的數(shù)據(jù)分片過程、進程或線程間的通信,以及并發(fā)控制方面帶來的系統(tǒng)開銷不但沒有增加性能,反而降低了原有性能。實現(xiàn)上,如何在優(yōu)化器里規(guī)劃好并行計劃也是很多數(shù)據(jù)庫做不到的。

PostgreSQL的并行查詢功能主要由PostgreSQL社區(qū)的核心開發(fā)者Robert Haas等人開發(fā)。從Robert Haas的個人博客了解到,社區(qū)開發(fā)PostgreSQL的并行查詢特性時間表如下:

  • 2013年10月,執(zhí)行框架上做了Dynamic Background Workers和Dynamic Shared Memory兩個調(diào)整

  • 2014年12月,Amit Kapila提交了一個簡單版的parallel sequential scan的patch;

  • 2015年3月,正式版的parallel sequential scan的patch被提交;

  • 2016年3月,支持parallel joins和parallel aggregation;

  • 2016年4月,作為9.6的新特性發(fā)布。

PostgreSQL的并行查詢在大數(shù)據(jù)量(中間結(jié)果在GB以上)的Join、Merge場合,效果比較明顯。效果上,因為系統(tǒng)開銷,投入的資源跟性能提升并不是線性的,比如增加4個worker,性能則可能提升2倍左右,而不是4倍。通過TPCH的測試效果,表明在Ad-Hoc查詢場景,普遍都有加速效果。

并行查詢功能說明

現(xiàn)在支持的并行場景主要是以下3種:

  • parallel sequential scan

  • parallel join

  • parallel aggregation

鑒于安全考慮,以下4種場景不支持并行:

  • 公共表表達式(CTE)的掃描

  • 臨時表的掃描

  • 外部表的掃描(除非外部數(shù)據(jù)包裝器有一個IsForeignScanParallelSafeAPI)

  • 對InitPlan或SubPlan的訪問

使用并行查詢,還有以下限制:

  • 必須保證是嚴格的read only模式,不能改變database的狀態(tài)

  • 查詢執(zhí)行過程中,不能被掛起

  • 隔離級別不能是SERIALIZABLE

  • 不能調(diào)用PARALLEL UNSAFE函數(shù)

并行查詢有基于代價策略的判斷,譬如小數(shù)據(jù)量時默認還是普通執(zhí)行。在PostgreSQL的配置參數(shù)中,提供了一些跟并行查詢相關(guān)的參數(shù)。我們想測試并行,一般設(shè)置下面兩個參數(shù):

  • force_parallel_mode:強制開啟并行模式的開關(guān)

  • max_parallel_workers_per_gather:設(shè)定用于并行查詢的worker進程數(shù)

一個簡單的兩表Join查詢場景,使用并行查詢模式的查詢計劃如下:

PostgreSQL如何實現(xiàn)并行查詢

PostgreSQL如何實現(xiàn)并行查詢

并行查詢開啟后,解析器會生成一份Gather…Partial風(fēng)格的執(zhí)行計劃,這意味著到Executor層,會將Partial部分的計劃并行執(zhí)行。

執(zhí)行計劃里可以看到,在做并行查詢時,額外創(chuàng)建了2個worker進程,加上原來的master進程,總共3個進程。Join的驅(qū)動表數(shù)據(jù)被平均分配了3份,通過并行scan分散了I/O操作,之后跟大表數(shù)據(jù)分別做Join。

并行查詢的實現(xiàn)

PostgreSQL的并行由多個進程的機制完成。每個進程在內(nèi)部稱之為1個worker,這些worker可以動態(tài)地創(chuàng)建、銷毀。PostgreSQL在SQL語句解析和生成查詢計劃階段并沒有并行。在執(zhí)行器(Executor)模塊,由多個worker并發(fā)執(zhí)行被分片過的子任務(wù)。即使在查詢計劃被并行執(zhí)行的環(huán)節(jié),一直存在的進程也會充當一個worker來完成并行的子任務(wù),我們可以稱之為主進程。同時,根據(jù)配置參數(shù)指定的worker數(shù),再啟動n個worker進程來執(zhí)行其他子計劃。

PostgreSQL內(nèi)延續(xù)了共享內(nèi)存的機制,在每個worker初始化時就為每個worker分配共享內(nèi)存,用于worker各自獲取計劃數(shù)據(jù)和緩存中間結(jié)果。這些worker間沒有復(fù)雜的通信機制,而是都由主進程做簡單的通信,來啟動和執(zhí)行計劃。

PostgreSQL中并行的執(zhí)行模型如圖1所示。

PostgreSQL如何實現(xiàn)并行查詢

圖1 PostgreSQL并行查詢的框架

以上文的Hash Join的場景為例,在執(zhí)行器層面,并行查詢的執(zhí)行流程如圖2所示。

PostgreSQL如何實現(xiàn)并行查詢

圖2 并行查詢的執(zhí)行流程

各worker按照以下方式協(xié)同完成執(zhí)行任務(wù):

  • 首先,每個worker節(jié)點做的任務(wù)相同。因為是Hash Join,worker節(jié)點使用一個數(shù)據(jù)量小的表作為驅(qū)動表,做Hash表。每個worker節(jié)點都會維護這樣一個Hash表,而大表被平均分之后跟Hash表做數(shù)據(jù)Join。

  • 最底層的并行是磁盤的并行scan,worker進程可以從磁盤block里獲取自己要scan的block。

  • Hash Join后的數(shù)據(jù)是全部數(shù)據(jù)的子集。對于count()這種聚合函數(shù),數(shù)據(jù)子集上可以分別做計算,最后再合并,結(jié)果上可以保證正確。

  • 數(shù)據(jù)整合后,做一次總的聚合操作。

worker進程又是如何創(chuàng)建和運行的?首先來看worker的創(chuàng)建邏輯(參見圖3)。

PostgreSQL如何實現(xiàn)并行查詢

圖3 PostgreSQL的worker創(chuàng)建

PostgreSQL的并行處理,以worker動態(tài)創(chuàng)建為前提。worker可以由主進程初始化出來,并且在上下文中,先指定好入口函數(shù)。

并行查詢中,入口函數(shù)被指定為ParallelWorkerMain。而ParallelWorkerMain函數(shù)里,在完成一系列信號代理設(shè)定后,會調(diào)用ParallelQueryMain來執(zhí)行查詢。ParallelQueryMain創(chuàng)建了一個新的執(zhí)行器上下文,遞歸執(zhí)行并行子查詢計劃。

用來并行查詢的worker進程接收主進程的信號,比如一旦發(fā)送創(chuàng)建進程的信號,worker進程就會啟動,緊接著執(zhí)行ParallelWorkerMain函數(shù)。進而,ParallelQueryMain也會執(zhí)行,各個worker進程獨立執(zhí)行子計劃,執(zhí)行結(jié)果會存在共享內(nèi)存里。所有進程執(zhí)行結(jié)束后,master進程會去搜集共享內(nèi)存里的結(jié)果數(shù)據(jù)(tuple),做數(shù)據(jù)整合。

并行查詢的改進

并行查詢的特性公布后,不乏對并行的評價和之后的改進計劃。社區(qū)并行查詢的開發(fā)者在博客中提到準備做一個大的共享Hash Table,這樣Hash Join操作的并行度會進一步提升。

PostgreSQL如何實現(xiàn)并行查詢

圖4 創(chuàng)建大的Hash表共享數(shù)據(jù)

另外,對PostgreSQL而言,反倒是基于其folk出來的一些數(shù)據(jù)庫產(chǎn)品先于它做了并行查詢的特性,可以學(xué)習(xí)參考:

  • Postgres-XC的分布式框架

  • GreenPlum的MPP架構(gòu)

  • CitusDB的分布式

  • VitesseDB基于多線程的并行

  • Fujitsu的Fujitsu Enterprise PostgreSQL的并行

其中開源數(shù)據(jù)庫GreenPlum并行架構(gòu)很有借鑒意義。GreenPlum的并行查詢設(shè)計了一個專門的調(diào)度器來協(xié)調(diào)查詢?nèi)蝿?wù)的分配,而PostgreSQL沒有這樣的設(shè)計。關(guān)于GreenPlum的執(zhí)行框架,簡單講是以下三層結(jié)構(gòu):

  • 調(diào)度器(QD):調(diào)度器發(fā)送優(yōu)化后的查詢計劃給所有數(shù)據(jù)節(jié)點(Segments)上的執(zhí)行器(QE)。調(diào)度器負責(zé)任務(wù)的執(zhí)行,包括執(zhí)行器的創(chuàng)建、銷毀、錯誤處理、任務(wù)取消、狀態(tài)更新等。

  • 執(zhí)行器(QE):執(zhí)行器收到調(diào)度器發(fā)送的查詢計劃后,開始執(zhí)行自己負責(zé)的那部分計劃。典型的操作包括數(shù)據(jù)掃描、哈希關(guān)聯(lián)、排序、聚集等。

  • Interconnect:負責(zé)集群中各個節(jié)點間的數(shù)據(jù)傳輸

GreenPlum會根據(jù)數(shù)據(jù)分布情況做數(shù)據(jù)的廣播和重分布,這是PostgreSQL的并行模型可以借鑒的。

僅僅是一個大的Hash Table,在數(shù)據(jù)訪問上有串行的開銷,worker的并行仍然受限。如圖5所示,大表和小表Join的場景參考GreenPlum的數(shù)據(jù)廣播機制,驅(qū)動表的數(shù)據(jù)可以給每個worker進程準備一個拷貝,相當于廣播了一份數(shù)據(jù)。這樣數(shù)據(jù)被高度共享,并行的效果會更好。

除了PostgreSQL生態(tài)的數(shù)據(jù)庫,關(guān)系型數(shù)據(jù)庫老大哥Oracle在并行查詢上已經(jīng)積累了30年的經(jīng)驗,也需要借鑒。在Oracle的官方手冊中,有對其并行查詢機制做出的說明。

PostgreSQL如何實現(xiàn)并行查詢

圖5 借鑒GreenPlum的廣播機制提升并行效果

Oracle在每個操作環(huán)節(jié),都能把數(shù)據(jù)高度分片,可以參考圖6所示的Hash Join的并行。

PostgreSQL如何實現(xiàn)并行查詢

圖6 Oracle的Hash Join操作的并行流程

而在內(nèi)部并行控制上,數(shù)據(jù)被分組后,不管是scan還是排序,幾組worker對分組的數(shù)據(jù)都能分治。

也就是說Oracle做到了操作符(Operator)Level的并行。在每個操作中,把數(shù)據(jù)分片后動態(tài)的并行運算??梢钥吹絆racle的并行查詢在做Operator級別的并行,每個操作環(huán)節(jié),都能把數(shù)據(jù)分片后分而治之,并行程度非常高。這對數(shù)據(jù)的流轉(zhuǎn)要求也很高,數(shù)據(jù)和操作既能水平分治也能垂直分治。

PostgreSQL目前是任務(wù)級別的并行,將原先的執(zhí)行計劃垂直拆分成幾個可以分離的子任務(wù),并行實現(xiàn)簡單,但在大數(shù)據(jù)量時并行度不夠,而且共享內(nèi)存的訪問負荷加重,性能提升不明顯。

PostgreSQL如何實現(xiàn)并行查詢

圖7 Oracle內(nèi)部動態(tài)的并行操作

參考Oracle的方式,按上圖改進后,worker不再是單獨執(zhí)行1個任務(wù),而是隨時被調(diào)用執(zhí)行操作。數(shù)據(jù)根據(jù)操作分層、分片、廣播,worker進程為數(shù)據(jù)操作服務(wù),而不是數(shù)據(jù)為worker服務(wù)。這樣在超大規(guī)模數(shù)據(jù)的場景,驅(qū)動表作為producer做數(shù)據(jù)partition,外表作為consumer做operator運算。多組這樣的操作產(chǎn)生的并行計算更自由,性能也更有想象空間,也是我們團隊目前在嘗試的方向。

PostgreSQL如何實現(xiàn)并行查詢

圖8 通過數(shù)據(jù)分組和worker分組提升PostgreSQL的并行

看完了這篇文章,相信你對“PostgreSQL如何實現(xiàn)并行查詢”有了一定的了解,如果想了解更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI