<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ## 背景 隨著PG9.5 項目的release,屬于PG9.6的代碼也陸續進入代碼主干,其中最讓人激動的特性并行查詢終于進入了核心代碼。pger們對這個新特性期待了太久的時間,代碼剛提交我們就迫不及待的拿到,從設計到性能進行一番探究,并通過本文介紹給大家。 ## 并行技術的過去和未來 這是個很困難的工作,要說清楚它需要講清楚并行技術相關的一些背景。 PG 目前的架構是基于多進程的,必要的信息通過共享內存這樣的機制來傳遞。 該架構的好處是: 1. 代碼相對簡單; 2. 在多CPU環境下多會話任務可以由操作系統來調度; 3. 多進程程序相對穩定。 不幸的是,雖然多會話任務可以利用操作系統并行調度滿足需求,但是單個任務卻只能最多使用一個CPU和一個IO通道。最近的計算機架構發展呈現出這樣的發展趨勢 1. 單個CPU的運算能力沒有大增長; 2. 越來越多的CPU核心; 3. SSD 存儲的崛起 I/O 延遲急劇降低(尤其隨機讀寫)。 但是數據庫要處理的單個會話任務的復雜程度卻急劇增加(想想復雜的多表JOIN任務、大表掃描任務、聚合操作和大量數據排序任務,再想想OLAP報表SQL)。單個任務的處理能力越來越成為了數據庫任務處理的瓶頸. PG發展路線是相對保守的,即使在這樣的趨勢下,已經在多個方面使用了并行技術。 1. 利用部分OS系統調度的并行IO調度(`effective_io_concurrency`,已完成); 2. 并行邏輯備份和恢復技術(已完成); 3. 并行執行器(in pg96)。 對于并行執行器,也就是本文討論的內容,相對于其他的技術點難度顯然大得多。 對于目前的架構,單個SQL任務的執行被明顯的分為: 1. 語法分析語義識別; 2. 查詢重寫; 3. 產生查詢計劃; 4. 執行查詢計劃。 一共4個大的階段。并行技術很難把這幾個明顯的階段并行起來執行,也不可能把某一階段的工作提前。但是把執行查詢計劃這個階段并行起來是可能的,也就是并行執行器。 ## 設計思路 整個設計可以分為下面幾個大的部分 1. 一套用于并行執行框架的基礎設施 包括容錯機制,這部分工作涉及到的點很雜也很多,按照計劃在PG9.5之前就已經實現了其中的大部分。其中很重要的是容錯機制,主進程需要了解屬于自己工作進程的執行狀態,處理工作進程執行過程中發生的任何錯誤,還有動態工作進程,動態共享內存API等等工作進程消息處理。 2. 修改優化器,在傳統的代價模型基礎上增加計算并行執行路徑的的代價數據,優化器能夠輸出并行執行計劃。增加并行執行節點相關的path、plan,用于存放并行相關的代價信息。 3. 開發一套用于多進程間同步數據的機制,目前的實現是開辟共享內存。當然也有其他選擇,發送和接受數據的格式和形式也需要設計。 4. 動態啟動多個工作進程,把查詢計劃中部分任務下發給它們執行 需要重組目前傳統的執行器流程,也就是在目前執行器上面添加用戶并行處理的執行節點:1)并行掃描節點,2)數據發送接收節點。 ## 結合代碼進行說明 還是從設計思路的4個方面講。 基礎設施 如上面的描述,這部分相當的雜,這些都是實現并行執行的技術設施。下面列舉主要的部分: 1. 動態共享內存,9.4完成,并提供了幾種底層的實現選擇(不同的OS選擇不同),參考參數?`dynamic_shared_memory_type`; 2. 共享內存消息隊列`shm_mq`,用于通過共享內存傳遞數據和狀態。通過核心函數?`shm_mq_receive`?,可以看到無論是數據還是錯誤消息都通過該機制來同步; 3. 主進程同步給工作進程相關的各種會話信息 * 動態庫 RestoreLibraryState() * 用戶信息,用戶登錄的DB BackgroundWorkerInitializeConnectionByOid() * 當前會話中的GUC參數,并行SQL所在的事務信合和狀態 RestoreGUCState() * 快照信息 RestoreSnapshot() * ComboCID信息 RestoreComboCIDState() 可以看到,為了讓工作進程完成部分工作,需要裝載主進程的很多上下文信息。這里有大量的工作,也意味著并行模式需要承擔一定的代價。這一點PG的并行模型的代價模型實現中有清晰的考慮。 完成了這一步,才能重用目前執行器中的大量現有流程。 修改優化器 考慮優化器的相應修改,我們知道PG優化器生成執行計劃是基于代價模型,并行執行在優化器的重點就是考慮如何準確估計并行執行的代價。 實現原理:新增并行相關的節點的執行path,并填充他們準確的 cost,讓它們參與到動態規劃或遺傳算法的迭代計算中。最終如果并行相關path最優,則創建完整的執行計劃交給執行器執行. 1. 新增的cost類型 * `parallel_setup_cost`?并行計劃啟動代價,對應工作進程的創建和上下文信息的傳遞所需要的代價。它也說明只有需要一定工作量的復雜SQL才有必要使用并行方式執行; * `parallel_tuple_cost`?主進程和工作進程間傳遞數據是需要消耗資源的,這取決于實現它的方式(目前消耗的資源多是內存拷貝和tuple的重組和解析); 上述代價是并行執行模型需要考慮的,結合統計信息中表上的其他信息,能預估出對應表或JOIN使用并行模型執行時的代價。 2. `cost_seqscan`?順序掃描采取了并行的執行方式,需要計算并行模式的代價。 順序掃描的代價分為3個部分?`startup_cost`?+?`cpu_run_cost`?+?`disk_run_cost`?并行模式下CPU 和 DISK 被分擔到了多個工作進程中,每個工作進程處理整個表中的一部分數據。相應的代價被重新評估. * `create_parallel_paths`?適合并行的表創建并行path并,并填充cost; * `standard_planner`?當然并行模式并不適合所有查詢,做邏輯優化階段需要關掉并行計劃的計算; * 當然,隨著工作進程能承擔的工作越多,更多的執行節點可以讓工作進程完成,在優化器中需要做適當的節點下推(push down)。 數據同步 這部分(`shm_mq`)底層使用共享內存在一個OS中,在多個獨立進程間同步數據。在實現上又抽象成了消息隊列的形式,用于工作進程和主進程間同步數據。 表上的數據(tuple)和錯誤消息被封裝成”消息”的形式發送給主進程,核心函數`shm_mq_sendv`?和`shm_mq_receive`可以看到,底層實現是通過在共享內存上用memcpy來做的。 執行流程重組 執行器的工作主要是改造傳統的逐層迭代方式以支持并行執行方式,當然是在重用之前代碼的基礎上,幾個關鍵的實現是: 1. ExecGather 添加用于接受工作進程發送數據的節點,內部調用了底層`shm_mq`?模塊中的API; 2. 在工作進程空間中,添加流程 ParallelQueryMain 用于工作進程完成工作并把數據通過?`shm_mq`?發送給主進程; 3. 改造順序掃描執行節點和下層的存取節點,支持按照blocknum為單位并行掃描同一個表。核心函數?`heap_parallelscan_nextpage`,他決定當前工作進程掃描任務是如何分配的。 該部分的工作重用了大量的舊的流程,但這和之前的執行器的工作模式有本質的區別,大量任務在獨立的進程空間中由OS 并行的調度執行,它們用?`shm_mq`?傳遞數據。 ## 總結 從公布的測試數據上來,部分場景在并行模式下能顯著提高性能。 由于并行模式有一定的開銷(被抽象成了各種成本),它并不是萬金油。當然,好的實現能讓它適應更多更復雜的場景。數據量特別小的場景不適合使用并行,這一點優化器能很好的評估成本,選擇正確的執行計劃。 其次,并行工作進程并不是越多越好,多到一定程度后性能的提升就不明顯了。 目前能放在工作進程中并行執行的任務還不多,只支持掃描類型的任務,但是整個并行框架是有了基本的雛形,相信幾輪迭代之后整套執行框架會越來越高效和穩定。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看