本文介紹如何在AnalyticDB for MySQL中對分組彙總查詢進行最佳化。
分組彙總流程
AnalyticDB for MySQL是分布式資料倉儲,其分組彙總查詢預設分為兩步:
完成資料的局部(PARTIAL)彙總。
局部彙總節點只需要佔用少量記憶體,彙總過程為流式過程,資料不會堆積在局部彙總節點上。
局部彙總完成後,資料根據分組欄位進行節點間的資料重分布,執行最終(FINAL)彙總。
局部彙總後的結果會通過網路傳輸到下遊Stage的節點(更多關於Stage的資訊,請參見影響查詢效能的因素)。因為資料已經經過了局部彙總,所以需要網路傳輸的資料較少,網路壓力較小。資料重分布完成後,執行最終彙總,在最終彙總節點,需要把一個分組的值及其彙總狀態維護在記憶體中,直到所有資料處理完成,以確保某個特定的分組值沒有新的資料需要處理,所以最終彙總節點可能會佔用較大的記憶體空間。
例如執行以下的SQL分組彙總語句。
SELECT sum(A), max(B) FROM tb1 GROUP BY C,D;
上述語句在進行分組彙總時,資料會首先在上遊Stage的Node1和Node2節點中執行局部彙總,局部彙總的結果是partial sum(A)
、partial max(B)
、C、D。局部彙總的結果會通過網路傳輸到下遊Stage的Node3和Node4節點中進行最終彙總。流程圖如下。
通過Hint最佳化分組彙總
適用情境
在大多數情境下,兩步彙總可以在記憶體和網路資源之間實現較好的平衡,但在分組彙總的分組數較多(即GROUP BY欄位的唯一值較多)等特殊情境下,兩步彙總不一定是最好的處理方法。
例如,在需要使用手機號碼或使用者ID進行分組的情境下,如果依舊使用典型的兩步彙總方式,那麼在局部彙總階段,可以被彙總的資料較少,但是局部彙總流程依舊會執行(例如,計算分組的HASH值、去重以及執資料列彙總函式)。由於分組數多,局部彙總階段並沒有減少網路傳輸的資料量,卻消耗了很多計算資源。
使用方法
為解決上述彙總度較低的分組彙總查詢問題,您可以在執行查詢時添加Hint
/*+ aggregation_path_type=single_agg*/
來跳過局部彙總,直接進行最終彙總,來減少不必要的計算開銷。說明如果在查詢SQL中使用了
/*+ aggregation_path_type=single_agg*/
Hint,那麼該SQL中所有的分組彙總查詢都會使用這個特定的最佳化流程,因此最佳的方式是先分析原始執行計畫中的彙總運算元的特點,並評估該Hint帶來的收益,最後決定是否使用該最佳化方案。最佳化說明
彙總度較低的情況下,上遊Stage的Node1和Node2節點進行局部彙總並沒有減少網路傳輸的資料量,卻消耗了很多計算資源。
最佳化後Node1和Node2節點不需要進行局部彙總,全部資料(即A、B、C、D)直接由下遊Stage的Node3和Node4節點進行最終彙總,從而減少了計算量,流程圖如下。
說明該最佳化不一定能起到最佳化記憶體使用量的目的,因為在彙總度較低的情況下,資料還是會大量地積攢在記憶體中進行去重和彙總以確保某個分組值的資料全部處理完成。