日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

SQL調優

本文為您介紹常見的SQL問題以及優化示例。

并行度優化

并行度是衡量并行計算程度的一個指標,從執行計劃上來看,例如ID為M1的任務,使用1000個Instance來執行,我們就說M1的并行度是1000。合理地設置并調整任務并行度,可以使任務執行效率更高。

并行度優化場景如下。

強制一個Instance執行

某些操作強制一個Instance執行任務,例如:

  • 做聚合的時候,沒有進行group by或者group by一個常量。

  • 窗口函數的over語句里指定partition by一個常量。

  • SQL中指定distribute bycluster by一個常量。

解決方案:針對此情形,建議您檢查這些操作是否必要,能否去掉,盡量取消類似操作,避免強制一個Instance執行任務。

Instance數量過多或過少

重要

調整并行度不一定是越多越好,Instance數量過多會從如下兩個方面影響執行速度:

  • Instance越多,等待資源的時間越長,排隊次數也更多。

  • 每個Instance初始化需要時間,并行度越高,初始化占用的總時間就越長,有效的執行時間占比就越低。

以下情形會導致使用很多Instance:

  • 需要讀取很多小分區的數據,例如一個數據查詢SQL語句讀取10000個分區,那么系統會強制使用10000個Instance。

    解決方案:您需要設計SQL,減少分區的數量,可以從進行分區裁剪、篩除不需要讀的分區、將大作業拆分成小作業方面進行考慮。

  • 每次讀取256 MB數據太少,導致Instance的執行時間太短,而由于輸入數據很大,反而導致了并行度過大,使Instance大多數時間在排隊等資源。

    解決方案:使用如下命令調大單個并發處理的數據大小,從而減少Instance數量。

    SET odps.stage.mapper.split.size=<256>;
    SET odps.stage.reducer.num=<并發數>;

Instance數量設置方法

  • 讀表的Task

    • 方法1:通過設置參數調整并行度。

      -- 設定一個map的最大數據輸入量,單位MB
      -- 默認256,區間[1,Integer.MAX_VALUE]
      SET odps.sql.mapper.split.size=<value>;
    • 方法2:MaxCompute提供split size hint方式,可以針對單個讀表操作來調整并行度。

      --設置split size大小為1MB,此hint會在讀src表時,按照1MB的大小來切分task
      SELECT a.key FROM src a /*+split_size(1)*/ JOIN src2 b ON a.key=b.key;
    • 方法3:在表級別按照大小、行數或指定并行度進行切分。

    由于方法1中odps.sql.mapper.split.size只支持Mapper Stage的整體設置,且最低為1 MB,必要時,您可以根據表的維度調整并行度,尤其是在表中每行數據的size較小,而后續計算負擔較重的情況下,可以減少并行處理的行數,從而提高任務的并行度。

    調整并行度的方式如下:

    • 設置表級別單個并行處理的分片數據大小。

      SET odps.sql.split.size = {"table1": 1024, "table2": 512};
    • 設置表級別單個并行處理的行數。

      SET odps.sql.split.row.count = {"table1": 100, "table2": 500};
    • 設置表級別的并行度。

      SET odps.sql.split.dop = {"table1": 1, "table2": 5};
    說明

    odps.sql.split.row.countodps.sql.split.dop只能用于內部表、非事務表和非聚簇表。

  • 非讀表的Task

    主要有如下三種方式調整并行度:

    • 方法1:調整odps.stage.reducer.num值。使用如下命令強制設置Reducer并行度,該設置將影響所有相關的Task。

      -- 設定Reduce Task的instance數量
      -- 可調整區間為[1,99999]
      SET odps.stage.reducer.num=<value>;
    • 方法2:調整odps.stage.joiner.num值。使用如下命令強制設置Reducer并行度,會影響所有相關的Task。

      -- 設定Joiner Task的instance數量
      -- 可調整區間為[1,99999]
      SET odps.stage.joiner.num=<value>;
    • 方法3:調整odps.sql.mapper.split.size值。

      非讀表Task的并行度會受到輸入Task的并行度影響,通過調整讀表Task的并行度間接調整非讀表Task的并行度。

窗口函數優化

如果SQL語句中使用了窗口函數,通常每個窗口函數會形成一個Reduce作業。如果窗口函數較多,會消耗過多的資源。您可以對符合下述條件的窗口函數進行優化:

  • 窗口函數在OVER關鍵字后面要完全相同,要有相同的分組和排序條件。

  • 多個窗口函數在同一層SQL中執行。

符合上述2個條件的窗口函數會合并為一個Reduce執行。SQL示例如下所示。

SELECT
RANK() OVER (PARTITION BY A ORDER BY B desc) AS RANK,
ROW_NUMBER() OVER (PARTITION BY A ORDER BY B desc) AS row_num
FROM MyTable;

子查詢優化

子查詢如下所示。

SELECT * FROM table_a a WHERE a.col1 IN (SELECT col1 FROM table_b b WHERE xxx);

當此語句中的table_b子查詢返回的col1的個數超過9999個時,系統會報錯為records returned from subquery exceeded limit of 9999。此時您可以使用Join語句來代替,如下所示。

SELECT a.* FROM table_a a JOIN (SELECT DISTINCT col1 FROM table_b b WHERE xxx) c ON (a.col1 = c.col1);
說明
  • 如果沒有使用DISTINCT關鍵字,而子查詢表c返回的結果中有相同的col1的值,可能會導致a表的結果數變多。

  • DISTINCT關鍵字會導致查詢在同一個Worker中執行。如果子查詢數據量較大,會導致查詢比較慢。

  • 如果業務上已經確保子查詢中col1列值無重復,您可以刪除DISTINCT關鍵字,以提高性能。

Join語句優化

當兩個表進行Join操作時,建議在如下位置使用WHERE子句:

  • 主表的分區限制條件可以寫在WHERE子句中(建議先用子查詢過濾)。

  • 主表的WHERE子句建議寫在SQL語句最后。

  • 從表分區限制條件不要寫在WHERE子句中,建議寫在ON條件或者子查詢中。

示例如下。

SELECT * FROM A JOIN (SELECT * FROM B WHERE dt=20150301)B ON B.id=A.id WHERE A.dt=20150301;
SELECT * FROM A JOIN B ON B.id=A.id WHERE B.dt=20150301; --不建議使用。此語句會先執行Join操作后進行分區裁剪,導致數據量變大,性能下降。
SELECT * FROM (SELECT * FROM A WHERE dt=20150301)A JOIN (SELECT * FROM B WHERE dt=20150301)B ON B.id=A.id;

聚合函數優化

使用wm_concat函數替代collect_list函數,實現聚合函數的優化,使用示例如下。

-- collect_list實現
SELECT concat_ws(',', sort_array(collect_list(key))) FROM src;
-- wm_concat實現更優
SELECT wm_concat(',', key) WITHIN GROUP (ORDER BY key) FROM src;


-- collect_list實現
SELECT array_join(collect_list(key), ',') FROM src;
-- wm_concat實現更優
SELECT wm_concat(',', key) FROM src;