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

Range Clustering

更新時(shí)間:

Range Clustering作為一種新的數(shù)據(jù)切分方式,提供了一個(gè)全局有序的數(shù)據(jù)分布,一是可以避免Hash Clustering可能造成的數(shù)據(jù)傾斜問(wèn)題;二是在數(shù)據(jù)有序分布的前提下,創(chuàng)建兩級(jí)索引(Index),支持對(duì)Clustering Key的區(qū)域查詢以及多鍵的組合查詢等場(chǎng)景。本文為您介紹如何在MaxCompute中使用Range Clustering。

背景信息

哈希聚簇(Hash Clustering)表有以下優(yōu)點(diǎn):

  • 對(duì)于等值的列條件查詢,可以利用Hash算法直接定位到對(duì)應(yīng)的哈希桶(Bucket Pruning),如果桶內(nèi)數(shù)據(jù)排序存儲(chǔ),還可以進(jìn)一步利用索引定位,從而減少數(shù)據(jù)掃描量,提高查詢效率。

  • 如果對(duì)不同表某一列上做Join,其中一張表因?yàn)橐呀?jīng)對(duì)其中一列做Hash分布,可以省掉Shuffle的步驟(稱之為Shuffle Remove),進(jìn)而節(jié)省計(jì)算資源。

關(guān)于Hash Clustering功能的詳細(xì)介紹請(qǐng)參見(jiàn)Hash Clustering

但是Hash Clustering也有一些局限性:

  • 使用Hash算法分桶,有可能產(chǎn)生Data Skew的問(wèn)題。和Join Skew一樣,這是Hash算法本身固有的局限性,輸入數(shù)據(jù)存在某些特定的數(shù)據(jù)分布時(shí),可能造成傾斜,進(jìn)而導(dǎo)致各個(gè)哈希桶之間數(shù)據(jù)量差異較大。因?yàn)镠ash Clustering之后,并發(fā)處理單位往往是一個(gè)桶,如果哈希桶數(shù)據(jù)量不一致,往往容易造成長(zhǎng)尾現(xiàn)象。

  • Bucket Pruning只支持等值查詢。因?yàn)槭褂霉7滞胺椒ǎ瑢?duì)于區(qū)間查詢比如使用某列值大于0這樣的條件,無(wú)法在哈希桶級(jí)別定位,只能把查詢下發(fā)到所有桶內(nèi)進(jìn)行。

  • 對(duì)于多個(gè)Cluster Key的組合查詢,只有所有Cluster Key都出現(xiàn)并且都為等值條件,才能達(dá)到優(yōu)化效果。

    比如,對(duì)于下表只有查詢條件包含C1=x AND C2=y才可以優(yōu)化。單獨(dú)的C1=x或者C2=y查詢條件皆無(wú)法利用Hash Clustering特性加速。這是因?yàn)閷?duì)于組合鍵的情況做了Combine Hash,要求查詢的時(shí)候一定要成對(duì)出現(xiàn),否則無(wú)法定位哈希桶,也無(wú)法做Bucket Pruning。

    CREATE TABLE T2 (C1 int, C2 int, C3 string)
       CLUSTERED BY (C1, C2)
          SORTED by (C1, C2)
           INTO 1024 BUCKETS;

針對(duì)這些局限性,MaxCompute推出了新的Clustering方法,即Range Clustering。

功能簡(jiǎn)介

Range Clustering在對(duì)Cluster Key全排序的基礎(chǔ)上,將其值域空間切分成若干個(gè)不連續(xù)值域(Disjointed Range),每個(gè)Range作為一個(gè)Bucket,并且滿足如下條件:

  • 相同數(shù)值存在于同一個(gè)Bucket里面。

  • 每個(gè)Bucket包含數(shù)值個(gè)數(shù)盡可能接近。

舉一個(gè)簡(jiǎn)單的例子:假設(shè)有表T,定義如下。

CREATE TABLE T (C1 int) 
    RANGE CLUSTERED BY (C1) 
    SORTED BY (c1) 
    INTO 3 BUCKETS;

同時(shí),C1列取值為{ 1, 8, -3, 2, 4, 1, 1, 3, 8, 20, -8, 9 }。

在Range Clustering之后,得到如下3個(gè)Bucket:

  • Bucket 0 : { -8, -3, 1, 1, 1 }

  • Bucket 1 : { 2, 3, 4 }

  • Bucket 2 : { 8, 8, 9, 20 }

說(shuō)明
  • 每個(gè)Bucket所代表的Range可能是不連續(xù)的(Disjointed)。例如Bucket 1的Range是[2, 4],而Bucket 2的Range是[8, 20],(4, 8)這個(gè)區(qū)間是沒(méi)有數(shù)值的。

  • Range切分的目標(biāo)是讓每個(gè)桶的大小盡量接近,而不是Range大小接近。在運(yùn)算的時(shí)候,每個(gè)桶是一個(gè)并發(fā)的單位,桶的大小一致保證了數(shù)據(jù)沒(méi)有長(zhǎng)尾。但是由于數(shù)據(jù)在各個(gè)區(qū)間分布密度不一致,桶的大小一致并不代表Range大小一致。

Range的切分過(guò)程是MaxCompute自動(dòng)完成的,不需要手動(dòng)指定每一個(gè)Range。因?yàn)樵诖髷?shù)據(jù)場(chǎng)景下手動(dòng)指定Range不高效,往往也不現(xiàn)實(shí)。MaxCompute內(nèi)部會(huì)自動(dòng)對(duì)數(shù)據(jù)進(jìn)行排序、采樣,對(duì)各個(gè)區(qū)間的數(shù)據(jù)密度建立直方圖,最后通過(guò)合并計(jì)算各個(gè)區(qū)間直方圖,來(lái)實(shí)現(xiàn)最終理想的Range切分。

此外RANGE CLUSTERED BY可以和SORTED BY結(jié)合,從而保證了數(shù)據(jù)全局有序,在這個(gè)基礎(chǔ)上,MaxCompute將自動(dòng)創(chuàng)建兩級(jí)索引:Global Index和File Index,用于快速定位和查找鍵值,如下圖所示:range clustering

和Hash Clustering相比,Range Clustering優(yōu)勢(shì)如下:

  • 支持區(qū)間查詢。

    假設(shè)有查詢條件c < 3,則可以根據(jù)Global Index快速排除掉Bucket 2和Bucket 3,從而只在Bucket 0和Bucket 1中查找。Hash Clustering只能對(duì)等值查詢做Bucket Pruning。

  • 支持多個(gè)Cluster列的組合查找。

    假設(shè)使用RANGE CLUSTERED BY (c1, c2, c3) SORTED BY (c1, c2, c3),那么在Range切分和數(shù)據(jù)存儲(chǔ)都是按照c1、c2、c3排序,這就可以允許做更復(fù)雜的組合查詢,比如c1 = 100 AND c2 > 0或者c1 = 100 AND c2 = 50 AND c3 < 5,這個(gè)也是Hash Clustering無(wú)法支持的。

    重要

    在多鍵組合查詢時(shí),條件需要按順序列出排序鍵,并且只有最后一個(gè)Key允許使用區(qū)間條件。

  • Range Clustering提供了一個(gè)高效的全局ORDER BY實(shí)現(xiàn)。

    在沒(méi)有Range Clustering之前為了保證全局有序,MaxCompute只能通過(guò)一個(gè)Instance進(jìn)行ORDER BY排序,效率很低。使用Range Clustering之后做Range切分之后,各個(gè)Range可以并發(fā)分別排序,最后在組合到一起,效率極大提高。

使用說(shuō)明

Range Clustering的語(yǔ)法和Hash Clustering類似,比較大的區(qū)別是RANGE關(guān)鍵字以及Bucket數(shù)目對(duì)于Range Clustering是可以省略的。

創(chuàng)建Range Clustering表

您可以使用以下語(yǔ)句創(chuàng)建Range Clustering表。您需要指定Range Cluster Key、Bucket數(shù)目(可選)。Sort是可選項(xiàng),但在大多數(shù)情況下,建議和Range Cluster Key一致,以便取得最佳的優(yōu)化效果。

  • 命令語(yǔ)法

    CREATE TABLE [IF NOT EXISTS] <table_name>
                 [(<col_name> data_type [comment <col_comment>], ...)]
                 [comment table_comment]
                 [PARTITIONED BY (<col_name> data_type [comment <col_comment>], ...)]
                 [RANGE CLUSTERED BY (<col_name> [, <col_name>, ...])
                 [SORTED BY (<col_name> [ASC | DESC]
                 [, <col_name> [ASC | DESC] ...])]
                 [INTO <number_of_buckets> BUCKETS]]
                 [AS select_statement]
  • 使用示例。

    • 非分區(qū)表。

      CREATE TABLE T1 (a string, b string, c int)
                   RANGE CLUSTERED BY (c)
                   SORTED by (c)
                   INTO 1024 BUCKETS;
    • 分區(qū)表。

      CREATE TABLE T1 (a string, b string, c int)
                   PARTITIONED BY (dt int)
                   RANGE CLUSTERED BY (c)
                   SORTED by (c)
                   INTO 1024 BUCKETS;
  • 屬性說(shuō)明

    • RANGE CLUSTERED BY

      指定Range Cluster Key,MaxCompute將對(duì)指定一列或者多列進(jìn)行排序和采樣,并根據(jù)指定Bucket數(shù)目,切分到盡可能理想的若干個(gè)Range里面。為避免數(shù)據(jù)傾斜、避免熱點(diǎn),取得較好的并行執(zhí)行效果,Clustered By列適宜選擇取值范圍大、重復(fù)鍵值少的列。此外為了達(dá)到優(yōu)化目的,也應(yīng)該考慮選取常用的Aggregation Key或者Filter Key。

    • SORTED BY

      指定在Bucket內(nèi)字段的排序方式,建議Sorted By和Clustered By一致,以取得較好的性能。此外當(dāng)Sorted By子句指定之后,MaxCompute將自動(dòng)生成索引(Global Index和File Index),并且在查詢的時(shí)候利用索引來(lái)加速執(zhí)行。

    • INTO number_of_buckets BUCKETS

      和Hash Clustering不一樣,對(duì)于Range ClusteringINTO ... BUCKETS是可選項(xiàng)。如果不指定Bucket數(shù)目,MaxCompute將根據(jù)數(shù)據(jù)大小自動(dòng)決定分片數(shù)目。在大多數(shù)情況下,建議指定Bucket數(shù)目,以便根據(jù)實(shí)際情況來(lái)做優(yōu)化選擇。

      對(duì)于Bucket數(shù)目的選擇,和Hash Clustering類似,建議保持在每個(gè)Bucket 512MB ~ 1GB這樣的數(shù)據(jù)量,對(duì)于特別大的表,Bucket 數(shù)目可以大些,但建議不要超過(guò)4000。

更改表的Hash Clustering屬性

對(duì)于分區(qū)表支持通過(guò)ALTER TABLE語(yǔ)句,來(lái)增加或者去除Range Clustering屬性。

  • 命令語(yǔ)句

    --更改表為Range Clustering表
    ALTER TABLE <table_name> [RANGE CLUSTERED BY (<col_name> [, <col_name>, ...])
                             [SORTED BY (<col_name> [ASC | DESC] [, <col_name> [ASC | DESC] ...])]
                             [INTO <number_of_buckets> BUCKETS];
    --更改Range Clustering表為非Range Clustering表
    ALTER TABLE <table_name> NOT CLUSTERED;
  • 注意事項(xiàng)

    • ALTER TABLE語(yǔ)句改變聚集屬性,只對(duì)于分區(qū)表有效,非分區(qū)表一旦聚集屬性建立就無(wú)法改變。

    • ALTER TABLE語(yǔ)句只會(huì)影響分區(qū)表的新建分區(qū)(包括insert overwrite生成的),新分區(qū)將按新的聚集屬性存儲(chǔ),老的數(shù)據(jù)分區(qū)保持不變。

    • 由于ALTER TABLE語(yǔ)句只影響新分區(qū),所以該語(yǔ)句不可以再指定PARTITION。

ALTER TABLE語(yǔ)句適用于存量表,在增加了新的聚簇屬性之后,新的分區(qū)將做Range Clustering存儲(chǔ)。

表屬性顯式驗(yàn)證

在創(chuàng)建Range Clustering Table之后,可以通過(guò)如下命令來(lái)查看表屬性,Range Clustering屬性將顯示在Extended Info里面。

DESC EXTENDED <table_name>;

返回結(jié)果示例如下圖所示。表屬性驗(yàn)證對(duì)于分區(qū)表,除了使用以上命令查看表屬性之后,還可以通過(guò)以下命令查看分區(qū)的屬性。

DESC EXTENDED <table_name> partition(<pt_spec>);

返回結(jié)果示例如下圖所示。分區(qū)表range屬性驗(yàn)證

使用場(chǎng)景

過(guò)濾查詢優(yōu)化

Range Clustering保證了數(shù)據(jù)全局有序,在這個(gè)基礎(chǔ)上MaxCompute自動(dòng)創(chuàng)建了Global Index和File Index,利用數(shù)據(jù)的存儲(chǔ)特性,可以加快數(shù)據(jù)過(guò)濾(Filter)的效率。不僅僅可以優(yōu)化等值查詢,也可以優(yōu)化區(qū)間查詢。

例如對(duì)于一個(gè)簡(jiǎn)單的查詢條件id < 3,先在優(yōu)化器里面將查詢條件抽取出來(lái),并轉(zhuǎn)化成值域空間(-∞, 3)。這個(gè)時(shí)候就可以利用Global Index做Bucket Pruning,把不在這個(gè)區(qū)間的Bucket 2和Bucket 3都去掉。最后再利用每個(gè)Bucket文件自帶的Index,快速在文件內(nèi)部定位,這個(gè)過(guò)程稱之為謂詞下推(Predicate Pushdown),示意圖如下:過(guò)濾查詢優(yōu)化TPC-H Q6在100GB數(shù)據(jù)集上使用Range Clustering后進(jìn)行查詢,查詢語(yǔ)句如下。Q6是一個(gè)區(qū)間過(guò)濾的基礎(chǔ)上再做的聚合操作,使用Range Clustering可以利用兩級(jí)Index快速定位數(shù)據(jù),無(wú)論是執(zhí)行時(shí)間、CPU使用率和內(nèi)存使用率的性能都有數(shù)倍的提升。

select sum(l_extendedprice * l_discount) as revenue
  from tpch_lineitem l
 where l_shipdate >= '1994-01-01'
   and l_shipdate < '1995-01-01'
   and l_discount >= 0.05
   and l_discount <= 0.07
   and l_quantity < 24;

多鍵組合查詢

為了比較好的理解多鍵組合查詢場(chǎng)景,使用如下命令將mf_tab 表改造成Range Clustering表。

ALTER TABLE mf_project.mf_tab 
            RANGE CLUSTERED BY (project_name, name)
            SORTED BY (project_name, name)
            INTO 1024 BUCKETS;

這樣做的好處是,既可以在Project級(jí)別上做一些聚合查詢,示例命令如下:

SELECT COUNT(*)
  from mf_project.mf_tab
 WHERE project_name="xxxdw"
   AND ds="20180115"
   AND type="TABLE";

又可以用組合鍵來(lái)精確定位某張表,示例命令如下:

SELECT count(*)
  from mf_project.mf_tab
 WHERE project_name="xxxdw"
   AND name="adm_ctu_cle_kba_midun_trade_dd"
   AND type="TABLE";

甚至可以用于區(qū)域查詢,比如統(tǒng)計(jì)以adm開頭的表:

SELECT count(*)
  from mf_project.mf_tab
 WHERE project_name="xxxdw"
   AND name>="adm"
   AND name < "adn"
   AND type="TABLE";

以上查詢都可以充分利用Range Clustering全局排序的特性,下推查詢謂詞,減少表掃描的IO量以及過(guò)濾計(jì)算的CPU和內(nèi)存消耗。

對(duì)于多個(gè)Range Cluster Key組合的場(chǎng)景,是有一定要求的。對(duì)于RANGE CLUSTERED BY k0, k1, ..., kn,如果查詢用到了km,則k0, k1, ..., km-1都必須在查詢條件中且都是等值條件,才能取得索引加速最佳效果。

假設(shè)表T的Range Cluster Key為k1, k2 ,則有:

  • 查詢條件為k1 < 5 :可以Index加速。

  • k1 = 10 AND k2 = 20:可以Index加速。

  • k1 = 10 AND k2 < 0:可以Index加速。

  • k2 < 0:不可以Index加速,k1缺失。

  • k1 < 0 AND k2 > 0:可以Index加速部分,Index只過(guò)濾k1<0的條件,k2>0條件需要掃描。

Group By優(yōu)化

對(duì)于Range Clustering,由于數(shù)據(jù)全局有序,并且相同的鍵值在做Range切分的時(shí)候,放到了同一個(gè)Bucket里面,Aggregation計(jì)算就可以利用這個(gè)數(shù)據(jù)的物理屬性,節(jié)省掉Shuffle的步驟。

例如,對(duì)于如下對(duì)表T數(shù)據(jù)的Group By操作可以直接在一個(gè)Mapper Stage里面完成。

CREATE TABLE T (department int, team string, employee string)
       RANGE CLUSTERED BY (department, team)
       SORTED BY (c1, c2)
       INTO 1024 BUCKETS;

SELECT COUNT(*) from T GROUP BY department, team;
說(shuō)明

如果要取得最佳的GROUP BY優(yōu)化效果,GROUP BY Key需要和RANGE CLUSTERED BY Key一致。

Aggregate 優(yōu)化

foo結(jié)構(gòu)如下。

create table foo(a bigint, b bigint, c bigint)
       range clustered by (a,b)
       sorted by(a,b) into 3 buckets;

假設(shè)表foo的Range為:

Bucket 0: [1,1 : 3,3]
Bucket 1: [5,5 : 7,7]
Bucket 2: [8,8 : 9,9]

以上Bucket Range可以理解為:Bucket N: [lower bound values : upper bound values]。如果按照a來(lái)聚合的話,每個(gè)Bucket的范圍就變成:

Bucket 0: [1 : 3]
Bucket 1: [5 : 7]
Bucket 2: [8 : 9]

可以直接產(chǎn)生類似按照a、b聚合的執(zhí)行計(jì)劃(Plan),啟動(dòng)3個(gè)Instance對(duì)每個(gè)Bucket聚合,然后輸出結(jié)果后結(jié)束。

但是對(duì)于a的值橫跨多個(gè)Bucket的情況下,就會(huì)得到錯(cuò)誤的結(jié)果,示例如下。

Bucket 0: [1,1 : 3,3]
Bucket 1: [3,5 : 7,7]
Bucket 2: [7,8 : 9,9]

a有兩個(gè)值3和7,分別橫跨兩個(gè)Bucket,只有把擁有相同的a值的tuple放到同一個(gè)Instance里面去進(jìn)行聚合才能得到正確的結(jié)果。也就是像下面按照紅色虛線重新切分Bucket,指定每個(gè)Instance讀取的數(shù)據(jù)的范圍才行:歸并優(yōu)化但是該從哪個(gè)地方切分, 這時(shí)候就需要直方圖的幫助。對(duì)于Range Clustering表,在Clustering Key和Sort Key相同的情況下,當(dāng)往Range Clustering表插入數(shù)據(jù)的時(shí)候,每個(gè)Bucket對(duì)應(yīng)的Worker會(huì)每10000行采樣一個(gè)tuple,取其Clustering Keys的值,并保存到直方圖中,最后每個(gè)Bucket的直方圖會(huì)存到Clustermeta文件中。 這種直方圖被稱為等高直方圖(equi-depth histogram)。

說(shuō)明

目前僅在Clustering Key和Sort Key一樣的情況下才會(huì)采樣。

有了每個(gè)Bucket的直方圖就可以為每個(gè)Worker重新切分Bucket。切分原則如下:

  • 擁有相同Grouping Key的tuple必須被劃分到同一個(gè)Bucket中。

  • 每個(gè)Bucket中的數(shù)據(jù)盡量均勻的切分。

有了每個(gè)新的Bucket的起始值,每個(gè)Worker就可以讀取正確的數(shù)據(jù)范圍,并返回正確的結(jié)果。

使用TPC-H數(shù)據(jù)集中1TB的partsupp表來(lái)測(cè)試性能提升如何。首先使用如下命令將partsupp表改造為Range Clustering表:

CREATE TABLE partsupp ( PS_PARTKEY BIGINT NOT NULL,
                        PS_SUPPKEY BIGINT NOT NULL,
                        PS_AVAILQTY BIGINT NOT NULL,
                        PS_SUPPLYCOST  DECIMAL(15,2)  NOT NULL,
                        PS_COMMENT     VARCHAR(199) NOT NULL)
             RANGE CLUSTERED BY(PS_PARTKEY, PS_SUPPKEY)
             SORTED BY(PS_PARTKEY, PS_SUPPKEY) INTO 128 BUCKETS;

使用下面的Query進(jìn)行測(cè)試:

SELECT ps_partkey, count(*) c FROM partsupp GROUP BY ps_partkey;
  • 使用如下命令關(guān)閉優(yōu)化:

     set odps.optimizer.enable.range.partial.repartitioning=false;

    結(jié)果示例:關(guān)閉優(yōu)化

  • 使用如下命令打開優(yōu)化:

    set odps.optimizer.enable.range.partial.repartitioning=true;

    結(jié)果示例:打開優(yōu)化

由上圖可以看出,針對(duì)此查詢優(yōu)化后速度提升了57%、CPU的使用率降低了52%、內(nèi)存的使用降低了71%。當(dāng)然針對(duì)不同數(shù)據(jù)量、不同的查詢,可能得到性能提升的程度也不同。

Range表的Join優(yōu)化

  • 假設(shè)有兩個(gè)表:

    create table t1(a bigint, b bigint, c bigint, d bigint)
           range clustered by(a,b,c)
           sorted by(a,b,c) into 3 buckets;
    
    create table t2(a bigint, b bigint, c bigint, d bigint)
           range clustered by(a,b,c)
           sorted by(a,b,c) into 3 buckets;

    然后分別往兩個(gè)表里插入不同的數(shù)據(jù)。

    對(duì)于Hash Clustering表,只要兩個(gè)相Join的Hash Clustering表?yè)碛邢嗤瑪?shù)目的Bucket,那么兩個(gè)表對(duì)應(yīng)的Bucket里的數(shù)據(jù)就可以Join。與Hash Clustering表不同的是:即使相Join的兩個(gè)Range Clustering表?yè)碛邢嗤瑪?shù)目的Bucket,也不能簡(jiǎn)單地直接根據(jù)Bucket Id來(lái)進(jìn)行Join,因?yàn)槊總€(gè)Range Bucket所存儲(chǔ)的數(shù)據(jù)范圍(Boundary)很有可能會(huì)不同。兩個(gè)Range Clustering表相Join始終會(huì)產(chǎn)生如下圖所示有Shuffle的查詢計(jì)劃:hash clustering對(duì)此需要進(jìn)行改進(jìn),通過(guò)對(duì)兩個(gè)Range表的Boundary進(jìn)行對(duì)齊來(lái)重新劃分每個(gè)表的Bucket,即重新定義每個(gè)Instance要讀取的數(shù)據(jù)范圍。

  • 假設(shè)有兩個(gè)表:

    create table t1(a bigint, b bigint, c bigint, d bigint)
           range clustered by(a,b,c)
           sorted by(a,b,c) into 5 buckets;
    
    create table t2(a bigint, b bigint, c bigint, d bigint)
           range clustered by(a,b,c)
           sorted by(a,b,c) into 3 buckets;

    當(dāng)插入一定量的數(shù)據(jù)后得到如下的Bucket Boundary:bucket boundary對(duì)于如下Query:

    SELECT * FROM t1 JOIN t2 ON t1.a=t2.a AND t1.b=t2.b AND t1.c=t2.c;

    優(yōu)化器會(huì)取擁有較多Bucket數(shù)目的Boundary來(lái)和另外一個(gè)表的Boundary進(jìn)行對(duì)齊,然后得到每個(gè)表的新的Boundary,即如下圖所示:bucket優(yōu)化后這樣就產(chǎn)生了沒(méi)有Shuffle的查詢計(jì)劃:查詢計(jì)劃對(duì)于下面的查詢:

    SELECT * FROM t1 JOIN t2 ON t1.a=t2.a AND t1.b=t2.b;

    優(yōu)化器會(huì)先對(duì)每個(gè)表按照a、b兩個(gè)列重新劃分Bucket,然后再將切分好的Bucket進(jìn)行對(duì)齊再次切分,從而得到每個(gè)表的每個(gè)Bucket所需要讀取的數(shù)據(jù)范圍,進(jìn)而產(chǎn)生像上圖那樣沒(méi)有Shuffle的查詢計(jì)劃。

  • 性能測(cè)試

    • 表改造

      用TPC-H Q2在1TB的數(shù)據(jù)表進(jìn)行測(cè)試,對(duì)part表和partsupp表進(jìn)行Range Clustering的改造,其他表保持不變:

      CREATE TABLE PARTSUPP ( PS_PARTKEY BIGINT NOT NULL,
                              PS_SUPPKEY BIGINT NOT NULL,
                              PS_AVAILQTY BIGINT NOT NULL,
                              PS_SUPPLYCOST  DECIMAL(15,2)  NOT NULL,
                              PS_COMMENT VARCHAR(199) NOT NULL)
                   RANGE CLUSTERED BY(PS_PARTKEY, PS_SUPPKEY)
                   SORTED BY(PS_PARTKEY, PS_SUPPKEY)
                   INTO 128 BUCKETS;
      CREATE TABLE PART ( P_PARTKEY BIGINT NOT NULL,
                          P_NAME VARCHAR(55) NOT NULL,
                          P_MFGR CHAR(25) NOT NULL,
                          P_BRAND CHAR(10) NOT NULL,
                          P_TYPE  VARCHAR(25) NOT NULL,
                          P_SIZE   BIGINT NOT NULL,
                          P_CONTAINER   CHAR(10) NOT NULL,
                          P_RETAILPRICE DECIMAL(15,2) NOT NULL,
                          P_COMMENT VARCHAR(23) NOT NULL)
                   RANGE CLUSTERED BY(P_PARTKEY)
                   SORTED BY(P_PARTKEY)
                   INTO 64 BUCKETS;

      TPC-H Q2的內(nèi)容如下:

      select s_acctbal,
             s_name,
             n_name,
             p_partkey,
             p_mfgr,
             s_address,
             s_phone,
             s_comment
        from part,
             supplier,
             partsupp,
             nation,
             region
       where p_partkey = ps_partkey
         and s_suppkey = ps_suppkey
         and p_size = 15
         and p_type like '%BRASS'
         and s_nationkey = n_nationkey
         and n_regionkey = r_regionkey
         and r_name = 'EUROPE'
         and ps_supplycost = (select min(ps_supplycost)
                                from partsupp, supplier, nation, region
                               where p_partkey = ps_partkey
                                 and s_suppkey = ps_suppkey
                                 and s_nationkey = n_nationkey
                                 and n_regionkey = r_regionkey
                                 and r_name = 'EUROPE')
        order by s_acctbal desc, n_name, s_name, p_partkey limit 100;
    • 測(cè)試結(jié)果

      • 使用如下命令關(guān)閉優(yōu)化:

         set odps.optimizer.enable.range.partial.repartitioning=false;

        結(jié)果示例:關(guān)閉優(yōu)化

      • 使用如下命令打開優(yōu)化:

        set odps.optimizer.enable.range.partial.repartitioning=true;

        結(jié)果示例:開啟優(yōu)化

      對(duì)比可以看出,優(yōu)化后不但有兩個(gè)Stage的減少,速度提升了約21.4%,而且CPU的消耗減少了約35.4%,內(nèi)存的使用也減少了約54.6%。

全局排序加速

Range Clustering還可以用來(lái)做全局排序加速。在普通的ORDER BY場(chǎng)景,為保證全局有序,所有的排序數(shù)據(jù)合并到一個(gè)單獨(dú)的Instance運(yùn)行,這就無(wú)法發(fā)揮并行處理的優(yōu)勢(shì)。利用Range Clustering的paritition步驟,可以實(shí)現(xiàn)并發(fā)多路全排序。首先對(duì)數(shù)據(jù)取樣并劃分Range,然后對(duì)各個(gè)Range做并發(fā)排序,最后得到的就是全局有序的結(jié)果。

需要注意的是,排序結(jié)束以后,修改表或分區(qū)存儲(chǔ)時(shí)仍然包括了多個(gè)文件(Buckets),在消費(fèi)數(shù)據(jù)時(shí),如果要保證全局有序,需要按Bucket順序讀取文件。

Range Clustering的全排序加速缺省關(guān)閉,如果需要打開,請(qǐng)使用以下Flag。

set odps.optimizer.distribute.ordering.enable=true;

局限性和注意事項(xiàng)

Range Clustering和Hash Clustering比較,有優(yōu)勢(shì)的同時(shí)在某些方面也有一些局限:

  • Range Clustering在數(shù)據(jù)生成的代價(jià)比Hash Clustering要高。Hash Clustering只是做一個(gè)簡(jiǎn)單的Hash操作和排序,但是對(duì)于Range而言,需要做數(shù)據(jù)采樣,排序,以及Histogram的合并等等,總體的代價(jià)(運(yùn)行時(shí)間、CPU使用率、Memory Cost)比Hash Clustering高。所以在Hash Clustering可以解決的問(wèn)題,就不需要用Range Clustering。

  • 不支持DYNAMIC PARTITION,以及INSERT INTO場(chǎng)景。

  • 對(duì)Join的支持方面只支持Inner Join、Left/Right Outer Join、Semi Join,不支持Anti Join和Full Outer Join。

  • Range Clustering表的Range Cluster Key必須和Sort Key相同,比如對(duì)于表foo中range clustered by (a,b) sorted by (a,b),本文中的優(yōu)化可以生效;但是對(duì)于表bar中range clustered by(a,b) sorted by (b,a),本文中的優(yōu)化就不會(huì)生效。

  • Join Key和Group Key必須為Range Clustering key的全部或者前綴。比如range clustered by(a,b,c) sorted by(a,b,c),對(duì)于Join Key和Group Key為a、a,ba,b,c的查詢才能應(yīng)用本文中的優(yōu)化;對(duì)于Join Key或Group Key為ba,c的查詢就無(wú)法應(yīng)用本文中的優(yōu)化。

  • 對(duì)于分區(qū)表,如果讀取的Range Clustering表涉及兩個(gè)或兩個(gè)以上的分區(qū)無(wú)法應(yīng)用本文中的優(yōu)化。目前本文中的優(yōu)化只針對(duì)單個(gè)分區(qū)的分區(qū)表和非分區(qū)表有效。