HIVE學習三:partition和bucket及Join

Partition

爲什麼需要Partition

由於hive執行一條簡單的sql都會查詢整個表,所以當表的數據量非常大時查詢速度會很慢。
基於此Hive可以將表劃分爲幾個分區,即將表基於某些分區列劃分爲幾個部分。每個表可以有一個或者多個分區。例如,有一個員工信息表,如果根據部門來分區的話,那麼查詢department="A"時就只需要去部門爲A的分區數據中找即可,而不用掃描整個表了,極大地提高了查詢的性能。

如何創建Partition

下面是整個建表語句,不僅僅包括分區,還包括bucket等

CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name
[(col_name data_type [column_constraint_specification] [COMMENT col_comment], ... [constraint_specification])]
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]
[CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]
[ROW FORMAT row_format]
[STORED AS file_format]
[LOCATION hdfs_path]

例如,創建如下的分區表,其中以yoj來作爲分區列,yoj表示year of join

create external table test_part(
id int, name string, dept string)
partitioned by(yoj string)
row format delimited fields terminated by ','
stored as textfile;

創建兩個輸入文件
/root/python_dirs/year/2009目錄下有文件file2, 內容如下

1, sunny, SC
2, animesh, HR

/root/python_dirs/year/2010目錄下有文件file3, 內容如下

3, sumeer, SC
4, sarthak, TP

分別將兩個文件導入到分區表裏

load data local inpath '/root/python_dirs/year/2009/file2' into table test_part partition(yoj='2009');
load data local inpath '/root/python_dirs/year/2010/file3' into table test_part partition(yoj='2010');

然後通過show partitions test_part可查看當前test_part表有哪些分區
在這裏插入圖片描述
在hdfs上對應的就是兩個目錄yoj=2009yoj=2010
在這裏插入圖片描述
可通過alter table test_part drop if exists partition(yoj="2010");來刪除分區數據
在這裏插入圖片描述

Partition的兩種類型 static VS dynamic

兩種類型的區別在於如何導入分區數據。通常在將大文件加載到Hive表中時,靜態分區是首選。但是,如果你不知道有幾個分區,那麼此時就可以選擇動態分區。以上面的例子簡要說明下,我們知道有兩個文件內容分別屬於yoj=2009yoj=2010,所以需要手動導入兩次,那麼如果我有10個不同的yoj的值呢?那麼我們就需要手動導入10次,這時我們就可以選擇動態分區

生成測試數據

假設我們有如下一張經過清洗後的信息表student_dwd_ext,可以認爲是一張寬表。

create external table student_dwd_ext(
id int, name string, sex string, age int, id_card string, 
address string, phone_number string, job string,
company string, graduation_time string)
row format delimited fields terminated by '\t'
stored as textfile
location '/opt/wacos/student';

下面是通過faker來生成測試數據的代碼,需要通過pip install faker來安裝所需要的依賴包

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# **********************************************
#
#      Filename: generate_student_data.py
#
#        Author: WangTian
#   Description: 批量生成學生數據
#        Create: 2020-03-03 21:19:30
# Last Modified: 2020-03-03 21:19:30
#
# **********************************************


from faker import Faker

import sys
from threading import Thread


def generate_stu_by_index(start, end, faker, file_name):
    '''
    生成id在start和end之間的學生數據
    start : int
    end : int
    faker : 外部傳進來, Faker類的實例對象, locale=“zh_CN”
    file_name : string 要生成的文件名
    '''

    file_handler = open(file_name, mode="w")
    id = start
    f = faker
    while(id <= end):
        f = Faker(locale="zh_CN")
        name = f.name()
        sex = f.random_element(elements=("男", "女"))
        age = f.random_int(min=20, max=40)
        id_card = f.ssn()
        address = f.address().split(" ")[0]
        phone_number = f.phone_number()
        job = f.job()
        company = f.company()
        graduation_time = f.random_element(
            elements=("2012", "2013", "2014", "2015", "2016"))
        row = "\t".join([str(id), name, sex, str(age), id_card,
                         address, phone_number, job, company,
                         graduation_time])
        file_handler.write(row+"\n")
        id = id+1

    file_handler.close()


class run_thread(Thread):
    def __init__(self, id, start, end, faker, file_name):
        Thread.__init__(self)
        self._id = id
        self._start = start
        self._end = end
        self._faker = faker
        self._file_name = file_name

    def run(self):
        print("threadid={}, starting......".format(self._id))
        generate_stu_by_index(self._start, self._end,
                              self._faker, self._file_name)
        print("threadid={}, exit......".format(self._id))
        print("threadid={}, has generated {} rows, the generated file is {}".format(
            self._id, (self._end-self._start+1), self._file_name))


def multithread_generate(num):
    '''
    多線程生成學生數據文件
    num : 線程數
    '''
    i = 1
    len = 100
    faker = Faker(locale="zh_CN")
    while(i <= num):
        start = len*(i-1)+1
        end = len*i
        run = run_thread(i, start, end, faker,
                         "{}_{}_{}.txt".format(i, start, end))
        run.start()
        i = i+1


def main(num):
    '''
    main方法
    '''
    multithread_generate(num)


if __name__ == "__main__":
    print sys.getdefaultencoding()
    reload(sys)
    sys.setdefaultencoding('utf8')
    print sys.getdefaultencoding()
    main(int(sys.argv[1]))

上面的代碼保存並命名爲generate_student_data.py
執行python generate_student_data.py 20來生成2000條數據,其中20表示開啓20個線程,每個線程生成100條數據。執行完後部分結果截圖如下所示。
在這裏插入圖片描述
執行load data local inpath '/root/python_dirs/*.txt' overwrite into table student_dwd_ext;將生成的2000條數據導入到student_dwd_ext表裏,如下所示
在這裏插入圖片描述

動態分區驗證

創建一個分區表,以graduation_time來作爲分區列

create table student_part(
id int, name string, sex string, age int, id_card string, 
address string, phone_number string, job string,
company string)
partitioned by(graduation_time string)
row format delimited fields terminated by '\t'
stored as textfile;

然後通過動態分區的方式導入數據,但是必須要開啓動態分區的設置,否則會報如下圖所示的錯誤。

# 開啓動態分區的設置
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
set hive.exec.max.dynamic.partitions=1000;
set hive.exec.max.dynamic.partitions.pernode=100;

insert into table student_part partition(graduation_time)
select * from student_dwd_ext;

在這裏插入圖片描述
然後對結果進行了如下的驗證

select count(*),graduation_time from student_dwd_ext group by graduation_time;
select count(*) from student_part where graduation_time="2012";
select count(*) from student_part where graduation_time="2013";
show partitions student_part;

在這裏插入圖片描述
在這裏插入圖片描述

Bucket

爲什麼要引入Bucket

我們知道Hive的Partition已經可以將表分隔成多個文件(或目錄),但是,Partition只是在如下兩個場景中有明顯的效果

  • 有限的分區數
  • 分區之間數據大小幾乎是相等的

例如,當我們以country來進行分區時,大國對應的分區數據就很大,小國對應的分區數據就很小,那麼此時Partition就不是太理想了。
爲了解決這個問題,Hive提出了Bucketing的概念。這是一種非常有效的技術,能將表的數據分成大小几乎相同的易於管理的多個部分。

特點及優點

Bucketing是通過對bucketed columnhash function然後mod number of buckets
通過CLUSTERED BY語句將表分爲多個buckets
每個bucket是表目錄的一個文件。
Bucketing可以和Partitioning一起使用,也可以單獨使用

Bucketing有如下幾個優點

  • 將表的數據分成大小几乎相同的幾部分
  • 相對於沒有做bucket的表利於做sampling
  • map side join會更快

同樣地,Bucketing也有缺點,就是在導入數據到bucket table時需要手工指定和導入,而且導入的時間會比導入數據到Partition表要長,因爲數據要均勻分配嘛。

創建Bucket

如下所示,clustered by指定id來做bucket,然後通過sorted by來在bucket文件裏做排序。
其中clustered bysorted by的字段必須要在表的創建定義裏定義好,這裏是Partitioning不同的地方

create table student_bucket_part(
id int, name string, sex string, age int, id_card string, 
address string, phone_number string, job string,
company string)
partitioned by(graduation_time string)
clustered by (id) sorted by (age) into 16 buckets
row format delimited fields terminated by '\t'
stored as textfile;

導入數據。如果不能成功導入到bucket表的話,可能需要顯示打開bucket
set hive.enforce.bucketing=true; 2.x的版本已經不需要

insert into table student_bucket_part partition(graduation_time)
select * from student_dwd_ext;

查看HDFS,能發現如下所示,每個bucket就是一個單獨的文件
在這裏插入圖片描述

Table Sampling VS limit

hive裏的Table Sampling是從原始的大數據集中抽取小部分數據,和limit非常相似。
但它們之間是有不同點的。大多數情況下,limit會執行全表掃然後指定數目的結果,但是Sampling會選取一部分數據來執行查詢。
關於tablesample bucket x out of y的說明,y一般來說是bucket num的整數倍

假如bucket num爲32
TABLESAMPLE(BUCKET 6 OUT OF 8)就表示分成8個bucket爲一組,然後就選取每組的第6個即6, 14, 22, 304個編號的bucket
TABLESAMPLE(BUCKET 23 OUT OF 32)就表示分成32個bucket爲一組,然後就選取第23個bucket
TABLESAMPLE(BUCKET 3 OUT OF 64)就表示64個bucket爲一組,然後就選取第3
select id,name,sex,age,job,graduation_time from student_bucket_part 
tablesample(bucket 10 out of 128) where age between 20 and 30;

在這裏插入圖片描述

Partition和Bucket數據模型圖示

在這裏插入圖片描述

Join

介紹

hive的join和sql的join是非常類似的,都是將多個表連接起來獲取更多的字段信息。關於Hive Join我們需要知道以下幾點:

  • 只有Equality join纔是被允許的,即join裏的on語句只能有等於和不等於
  • 一個query語句裏可以有超過2張表來進行join,這是和sql join保持一致的。
  • LEFT, RIGHT, FULL OUTER join,這是和sql join保持一致的,不過mysql沒有full join
  • Joins are NOT commutative! Joins are left-associative regardless of whether they are LEFT or RIGHT joins,意思是a join bb join a是不同的,這不同於數學上的加法交換律,順序不同,哪個表去stream也是不同的,關於stream後面有介紹。不管是LEFT JOIN還是RIGHT JOIN都是從左開始join表的,至於數據以哪張表爲主就看是LEFT JOIN還是RIGHT JOIN

完整的join語法如下

join_table:
    table_reference [INNER] JOIN table_factor [join_condition]
  | table_reference {LEFT|RIGHT|FULL} [OUTER] JOIN table_reference join_condition
  | table_reference LEFT SEMI JOIN table_reference join_condition
  | table_reference CROSS JOIN table_reference [join_condition] (as of Hive 0.10)
 
table_reference:
    table_factor
  | join_table
 
table_factor:
    tbl_name [alias]
  | table_subquery alias
  | ( table_references )
 
join_condition:
    ON expression

Hive Join有四種類型,如下圖所示,和sql join是保持一致的,具體各個join是什麼意思我就不在這裏贅述。
在這裏插入圖片描述

官方的join exmaples

  • 如下的join語句都是正確的
SELECT a.* FROM a JOIN b ON (a.id = b.id)
SELECT a.* FROM a JOIN b ON (a.id = b.id AND a.department = b.department)
SELECT a.* FROM a LEFT OUTER JOIN b ON (a.id <> b.id)
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)
  • 如果join子句對於每個表都使用相同的列,則Hive將多個表上的join轉換爲單個map/reduce作業
    例如,下面的join語句的on條件裏都有b.key1,所以該join會轉換成一個MR作業
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)

例如,下面的join語句的on條件裏沒有相同的列,所以會轉換成兩個MR作業。 第一個MR作業是a join b,然後a join b的結果和cjoin作爲第二個MR作業。

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)
  • 在join的每個MR階段,最後一個表都是通過reducer傳遞的,其他前面的表被緩存到內存裏。因此將大表放在最後面是可以減少內存消耗的。
    例如,下面的join語句會轉換成一個MR作業,a和b表的數據就會被緩存到內存裏,c表通過reducer傳遞
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)

例如,下面的join語句會轉換成兩個MR作業。第一個MR作業緩存a表數據,b表通過reducer傳遞;第二個MR作業緩存a join b的結果數據,c表通過reducer傳遞

SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)
  • 在join的每個MR階段,要傳遞(stream)的表是可以顯示指定的
    例如,下面的join語句會轉換成一個MR作業,如果不指定/*+ STREAMTABLE(a) */,默認是c表去stream,a和b表的數據就會被緩存到內存。現在指定了/*+ STREAMTABLE(a) */,所以是b和c表的數據就會被緩存到內存,a表通過reducer傳遞。
    如果沒有顯示指定STREAMTABLE,默認要stream的表是最後一個。
SELECT /*+ STREAMTABLE(a) */ a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)
  • LEFT, RIGHT, and FULL OUTER join對於匹配不成功的時候是非常有效的,實際工作經常用
    例如,下面的LEFT OUTER JOIN語句對於a表的每行數據都會有返回結果。如果有b.key等於a.key那麼返回a.val, b.val,如果沒有b.key等於a.key那麼返回a.val,NULL。b表中和a.key不匹配的數據會被丟棄。
    FROM a LEFT OUTER JOIN b必須要寫在一行來保證a一定是在b的左邊,保留a表所有數據。
    FROM a RIGHT OUTER JOIN b必須要寫在一行,保留b表所有數據。
    FROM a FULL OUTER JOIN b必須要寫在一行,保留a表和b表所有數據。
SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key)
  • join發生在where語句前。所以如果想過濾join的輸出的話,可以在where語句裏過濾,也可以在join語句裏過濾
    考慮下面的sql語句,會返回a.val,b.val的數據集,然後在where進行過濾(既引用了a表字段也引用了b表字段)。對於沒有b.key等於a.key的row來說,返回的數據是a.val,NULL,而且b.ds的值也是NULL。也就是說b.ds='2009-07-07'會過濾掉所有沒有b.key等於a.key的a的row數據(那就有可能過濾多了)
SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key)
WHERE a.ds='2009-07-07' AND b.ds='2009-07-07'

那麼對於LEFT OUTER JOIN這種情況來說,應該採用下面的語句,join的結果已經預先就過濾掉了。RIGHT and FULL join也是同理。


SELECT a.val, b.val FROM a LEFT OUTER JOIN b
ON (a.key=b.key AND b.ds='2009-07-07' AND a.ds='2009-07-07')
  • Joins are NOT commutative! Joins are left-associative regardless of whether they are LEFT or RIGHT joins. 這句話我在上面join的介紹裏就已經說明的很清楚了。
    例如,a和b先做join,得到的結果再去做LEFT OUTER JOIN c,所以即使a.keyc.key存在但是b.key不存在,這條數據也會在a join b的階段被幹掉。

SELECT a.val1, a.val2, b.val, c.val
FROM a
JOIN b ON (a.key = b.key)
LEFT OUTER JOIN c ON (a.key = c.key)
  • LEFT SEMI JOIN以一種有效的方式實現了IN/EXISTS子查詢功能。LEFT SEMI JOIN的限制是右邊的表只能在join condition (ON-clause)裏引用,不能在WHERE或者SELECT等語句裏使用
    例如,
SELECT a.key, a.value
FROM a
WHERE a.key in
 (SELECT b.key
  FROM B);

就可以重寫成

SELECT a.key, a.val
FROM a LEFT SEMI JOIN b ON (a.key = b.key)
  • 如果join的表裏面有一個小表,那麼就可以將該join轉換成一個只有map的job,不需要reducer
    例如,b表足夠小,/*+ MAPJOIN(b) */就會將b表的所有數據加載到內存,對於a表的每個mapper,b表數據可以直接讀取。限制是a FULL OUTER JOIN b不能執行,因爲map join操作僅僅只能stream一張表,FULL OUTER JOIN就需要stream兩張表了。不建議使用/*+ MAPJOIN(b) */,而應該使用參數hive.auto.convert.join=true,開啓後hive會在運行時自動的將join轉換成map join(如果可以的話)
SELECT /*+ MAPJOIN(b) */ a.key, a.value
FROM a JOIN b ON a.key = b.key
  • 如果join的表是在on語句的列上做了bucket,且兩個表的bucket的數目是倍數關係,那麼兩表的bucket之間可以相互join
    例如,a表和b表都有4個bucket,下面的join會轉換成一個只有map的job。對於A的每個mapper,不用獲取B的所有數據,處理A的bucket-1的mapper僅僅只需要獲取B的bucket-1。但是這並不是默認行爲,需要通過設置set hive.optimize.bucketmapjoin = true來開啓
SELECT /*+ MAPJOIN(b) */ a.key, a.value
FROM a JOIN b ON a.key = b.key
  • 如果join的表是在on語句的列上做了bucket和sort,而且兩表有同樣的bucket數,那麼就可以優化成sort-merge join。在mapper裏,對應的bucket會相互join。
    例如,a表和b表都有4個bucket,下面的join會轉換成一個只有map的job。但是需要開啓參數來進行優化
set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true;

SELECT /*+ MAPJOIN(b) */ a.key, a.value
FROM A a JOIN B b ON a.key = b.key

Map Join

原理介紹

Hive裏的Map Join可以加速查詢,這個feature也叫做Map Side Join。上面的官方例子裏也簡要提到了Map Join的用法,這裏是從運行原理、參數、限制等方面來更加詳細的介紹該feature
join有一個開銷非常大的操作就是shuffle,這就降低了hive的查詢速度。我們可以用Map Side Join來加速查詢,因爲在join的表裏有一個小表是可以完整的加載到內存裏的。所以該join可以轉換成一個只有map沒有reducer的job,消去了shuffle過程。
在這裏插入圖片描述
MR task前,第一步就是創建一個MapReduce local task。這個本地的MR task會從HDFS上讀取小表數據,然後加載到內存的hash table裏,然後變成一個hash table文件。接着在MR task啓動前將這個hash table文件通過Hadoop Distributed Cache發送到每個mapper的本地磁盤上。這樣,所有的mapper就能加載這個hash table文件到mapper內存裏然後在map階段做join。

參數
hive.auto.convert.join
<property>
    <name>hive.auto.convert.join</name>
    <value>true</value>
    <description>Whether Hive enables the optimization about converting common join into mapjoin based on the input file size</description>
</property>

該參數默認值是true,當join的表裏找到一個大小小於25 MB(hive.mapjoin.smalltable.filesize)的表,那麼就將該join轉換爲map join

hive.auto.convert.join.noconditionaltask
<property>
    <name>hive.auto.convert.join.noconditionaltask</name>
    <value>true</value>
    <description>
    Whether Hive enables the optimization about converting common join into mapjoin based on the input file size.
    If this parameter is on, and the sum of size for n-1 of the tables/partitions for a n-way join is smaller than the
    specified size, the join is directly converted to a mapjoin (there is no conditional task).
    </description>
</property>
<property>
    <name>hive.auto.convert.join.noconditionaltask.size</name>
    <value>10000000</value>
    <description>
    If hive.auto.convert.join.noconditionaltask is off, this parameter does not take affect.
    However, if it is on, and the sum of size for n-1 of the tables/partitions for a n-way join is smaller than this size,
    the join is directly converted to a mapjoin(there is no conditional task). The default is 10MB
    </description>
</property>

假定有3表或者更多的表一起join的場景。如果所有的表都是小表且開啓hive.auto.convert.join,Hive會生成3個或多個map-side join。然而,如果第n個表的大小小於10 MB(hive.auto.convert.join.noconditionaltask.size),我們可以將這3個或多個map-side join變成一個map-side join

hive.auto.convert.join.use.nonstaged

可以將其設置爲true來避免這些情況的pres-taging,這些情況包括要map join的表不用過濾或者projection。當前,該參數不適用於vectorizationtez引擎

<property>
    <name>hive.auto.convert.join.use.nonstaged</name>
    <value>false</value>
    <description>
      For conditional joins, if input stream from a small alias can be directly applied to join operator without
      filtering or projection, the alias need not to be pre-staged in distributed cache via mapred local task.
      Currently, this is not working with vectorization or tez execution engine.
    </description>
</property>
Hive Map Side Join的限制
  • 主要的限制是我們是無法將Full outer join轉化爲map-side join的。這個在上面官方例子裏說過。
  • 對於left-outer join變成map-side join,右邊的表大小需要小於25 MB。
  • Union Followed by a MapJoin
  • Lateral View Followed by a MapJoin
  • Reduce Sink (Group By/Join/Sort By/Cluster By/Distribute By) Followed by MapJoin
  • MapJoin Followed by Union
  • MapJoin Followed by Join
  • MapJoin Followed by MapJoin
測試

先創建一張表company_new

create table company_new
row format delimited fields terminated by '\t'
stored as textfile
AS
select count(*) ct,company from student_part group by company order by ct desc;

將student_dwd_ext表和company_new表進行join,查看執行計劃

explain select a.*, b.ct from student_dwd_ext a, company_new b where a.company=b.company and a.company="凌雲科技有限公司";

如下圖所示,只有Map階段,沒有reduce,說明已經變成了map-side join
在這裏插入圖片描述
在關閉掉hive.auto.convert.join後再次查看其查詢計劃,如下圖所示,就是正常的join,有Reduce

set hive.auto.convert.join=false;
explain select a.*, b.ct from student_dwd_ext a, company_new b where a.company=b.company and a.company="凌雲科技有限公司";

在這裏插入圖片描述
查詢時間上也有差距,這裏我就不展示圖片了。

Bucket Map Join

當要join的表很大,且join on的列剛好是bucket的列,還需要一個表的bucket的數目是另一個表的bucket數目的倍數,那麼我們就可以使用Bucket Map Join
在這裏插入圖片描述
假如一個表有2個bucket,那麼另一個表的bucket的數目必須是2的倍數。而且表的每個bucket是可以放的進內存例如a表的bucket-a1大小要足夠小,這樣才能執行map side join,否則就只能執行普通的join。這樣,在mapper端就只需要獲取相對應的bucket就行了,而不用獲取整個表。這樣就能大大提高性能。還有一點需要保證的是,數據不能在bucket map join裏做排序。

默認情況下,bucket map join是不會開啓的,需要設置下面的參數來開啓優化。

set hive.optimize.bucketmapjoin = true;
set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;

bucket map join的使用場景總結爲以下五點

  1. 所有的表是非常大的
  2. 表join on的列恰好是bucket的列
  3. 一個表的bucket的數目是另一個表的bucket數目的倍數
  4. 表的每個bucket必須要足夠小(即對應的bucket數目應該要很大)
  5. 數據不能排序

bucket map join的缺點也是非常明顯,也就是上面的第2點,只能用在特定的sql join語句裏。

Sort Merge Bucket Map Join

使用要求如下

  1. 所有的表是非常大的
  2. 表join on的列恰好是bucket的列同時也是sort的列
  3. 所有join的表的bucket的數目必須是相同的

需要設置以下參數來開啓

set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
set hive.auto.convert.sortmerge.join=true;
set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true;

Sort Merge Bucket Map Join的缺點也是非常明顯,限制很高。

join優化的總結

上面的這些優化參數並不一定會帶來更快的查詢速度。假如選擇Sort Merge Bucket Map Join,在執行join前會首先對join的表進行排序,這就是增加的開銷。map join也會增加內存的開銷。所以這都是一個trade-off的過程。
有可能簡單的join就有很好的性能,而上面的優化參數沒有效果。所以這時就可以考慮調整MapReduce或者Hive配置如內存使用、並行度等來優化常規的join。

參考網址

faker簡單使用
faker官網
python-multithreading
hive-static-vs-dynamic-partition
data-flair-hive-parititions
LanguageManual+Sampling
tablesamplebucket-x-out-of-y
bucketing-in-hive
LanguageManual+Joins
map-join-in-hive
LanguageManual+JoinOptimization
hive-efficient-join-of-two-tables

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章