大數(shù)據(jù)從業(yè)者必知必會的Hive SQL調(diào)優(yōu)技巧
摘要:在大數(shù)據(jù)領(lǐng)域中,Hive SQL被廣泛應(yīng)用于數(shù)據(jù)倉庫的數(shù)據(jù)查詢和分析。然而,由于數(shù)據(jù)量龐大和復(fù)雜的查詢需求,Hive SQL查詢的性能往往不盡人意。本文針對Hive SQL的性能優(yōu)化進(jìn)行深入研究,提出了一系列可行的調(diào)優(yōu)方案,并給出了相應(yīng)的優(yōu)化案例和優(yōu)化前后的SQL代碼。通過合理的優(yōu)化策略和技巧,能夠顯著提升Hive SQL的執(zhí)行效率和響應(yīng)速度。
關(guān)鍵詞:Hive SQL;性能優(yōu)化;調(diào)優(yōu)方案;優(yōu)化案例
1. 引言
隨著大數(shù)據(jù)時(shí)代的到來,數(shù)據(jù)分析和挖掘變得越來越重要。Hive作為Hadoop生態(tài)系統(tǒng)中的數(shù)據(jù)倉庫工具,扮演著重要的角色。然而,由于數(shù)據(jù)量龐大和查詢復(fù)雜性,Hive SQL查詢的執(zhí)行效率往往較低。因此,深入了解Hive SQL調(diào)優(yōu)技巧對于數(shù)據(jù)工程師和數(shù)據(jù)分析師來說至關(guān)重要。
2. 先做個(gè)自我反思
很多時(shí)候, Hive SQL 運(yùn)行得慢是由開發(fā)人員對于使用的數(shù)據(jù)了解不夠以及一些不良的使用習(xí)慣引起的。
?真的需要掃描這么多分區(qū)嗎?
比如,對于銷售明細(xì)事務(wù)表來說,掃描一年的分區(qū)和掃描一周的分區(qū)所帶來的計(jì)算、 IO 開銷完全是兩個(gè)量級,所耗費(fèi)的時(shí)間肯定也是不同的。作為開發(fā)人員,我們需要仔細(xì)考慮業(yè)務(wù)的需求,盡量不要浪費(fèi)計(jì)算和存儲資源。
?習(xí)慣使用select *這樣的方式,而不是用到哪些列就指定哪些列嗎?
比如,select coll, col2 from your_table ,另外, where 條件中也盡量添加過濾條件,以去掉無關(guān)的數(shù)據(jù)行,從而減少整個(gè) MapReduce 任務(wù)中需要處理、分發(fā)的數(shù)據(jù)量。
?需要計(jì)算的指標(biāo)真的需要從數(shù)據(jù)倉庫的公共明細(xì)層來自行匯總嗎?
是不是數(shù)倉團(tuán)隊(duì)開發(fā)的公共匯總層已經(jīng)可以滿足你的需求?對于通用的、管理者駕駛艙相關(guān)的指標(biāo)等通常設(shè)計(jì)良好的數(shù)據(jù)倉庫公共層肯定已經(jīng)包含了,直接使用即可。
??
3 查詢優(yōu)化
3.1 盡量原子化操作
盡量避免一個(gè)SQL包含復(fù)雜邏輯,可以使用中間表來完成復(fù)雜的邏輯。建議對作業(yè)進(jìn)行合理拆分,降低作業(yè)出問題重跑時(shí)資源的浪費(fèi)和下游時(shí)效的影響。
3.2 使用合適的數(shù)據(jù)類型
選擇合適的數(shù)據(jù)類型可以減小存儲空間和提高查詢效率。例如,將字符串類型轉(zhuǎn)換為整型類型可以節(jié)省存儲空間并加快查詢速度。
優(yōu)化案例
優(yōu)化前:
SELECT * FROM table WHERE age = '30';
優(yōu)化后:
SELECT * FROM table WHERE age = 30;
3.3 避免全表掃描
盡量避免全表掃描,可以通過WHERE子句篩選出需要的數(shù)據(jù)行,或者使用LIMIT子句限制返回結(jié)果的數(shù)量。
反面案例
天天全表掃描計(jì)算所有歷史數(shù)據(jù)。 map數(shù)超20萬。
Select * from table where dt<=’{TX_DATE}’
優(yōu)化案例1
優(yōu)化前:
--優(yōu)化前副表的過濾條件寫在where后面,會導(dǎo)致先全表關(guān)聯(lián)再過濾分區(qū)。
select a.* from test1 a left join test2 b on a.uid = b.uid where a.ds='2020-08-10' and b.ds='2020-08-10'
優(yōu)化后:
select a.* from test1 a left join test2 b on (b.uid is not null and a.uid = b.uid and b.ds='2020-08-10') where a.ds='2020-08-10'
優(yōu)化案例2
利用max函數(shù)取表最大分區(qū),造成全表掃描。
優(yōu)化前:
Select max(dt) from table
優(yōu)化后:
使用自定義(show partition 或 hdfs dfs –ls )的方式替代max(dt)
3.4 使用分區(qū)
數(shù)據(jù)分區(qū)是一種將數(shù)據(jù)按照某個(gè)字段進(jìn)行分組存儲的技術(shù),可以有效減少查詢時(shí)的數(shù)據(jù)掃描量。通過分區(qū)字段進(jìn)行數(shù)據(jù)過濾,可以只對目標(biāo)分區(qū)進(jìn)行查詢,加快查詢速度。
優(yōu)化案例
優(yōu)化前:
SELECT * FROM table WHERE date = '2021-01-01' AND region = 'A';
優(yōu)化后:
SELECT * FROM table WHERE partition_date = '2021-01-01' AND partition_region = 'A';
反面案例
代碼寫死日期,一次性不合理掃描2年+日志數(shù)據(jù)。map數(shù)超20萬,而且會越來越大,直到跑不出來。
Select * from table where src_mark=’23’ and dt between ‘2020-05-16’ and ‘{TX_DATE}’ and scr_code is not null
3.5 使用索引
在Hive SQL中,可以通過創(chuàng)建索引來加速查詢操作。通過在關(guān)鍵字段上創(chuàng)建索引,可以減少數(shù)據(jù)掃描和過濾的時(shí)間,提高查詢性能。
優(yōu)化案例
優(yōu)化前:
SELECT * FROM table WHERE region = 'A' AND status = 'ACTIVE';
優(yōu)化后:
CREATE INDEX idx_region_status ON table (region, status); SELECT * FROM table WHERE region = 'A' AND status = 'ACTIVE';
3.6 查詢重寫
查詢重寫是一種通過改變查詢語句的結(jié)構(gòu)或使用優(yōu)化的查詢方式,來改善查詢的性能的技巧。可以通過重寫子查詢、使用JOIN代替IN/EXISTS子查詢等方法來優(yōu)化查詢。
優(yōu)化案例
優(yōu)化前:
SELECT * FROM table1 WHERE id IN (SELECT id FROM table2 WHERE region = 'A');
優(yōu)化后:
SELECT * FROM table1 t1 JOIN (SELECT id FROM table2 WHERE region = 'A') t2 ON t1.id = t2.id;
3.7 謂詞下推
謂詞下推是一種將過濾條件盡早應(yīng)用于查詢計(jì)劃中的技術(shù)(即SQL語句中的WHERE謂詞邏輯都盡可能提前執(zhí)行),減少下游處理的數(shù)據(jù)量。通過將過濾條件下推至數(shù)據(jù)源,可以減少查詢數(shù)據(jù)量,提升查詢性能。
優(yōu)化案例
優(yōu)化前:
select a.*,b.* from a join b on a.name=b.name where a.age>30
優(yōu)化后:
SELECT a.*, b.* FROM ( SELECT * FROM a WHERE age > 30 ) a JOIN b ON a.name = b.name
3.8 不要用COUNT DISTINCT
COUNT DISTINCT操作需要用一個(gè)Reduce Task來完成,這一個(gè)Reduce需要處理的數(shù)據(jù)量太大,就會導(dǎo)致整個(gè)Job很難完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替換,雖然會多用一個(gè)Job來完成,但在數(shù)據(jù)量大的情況下,這個(gè)絕對是值得的。
優(yōu)化案例
優(yōu)化前:
select count(distinct uid) from test where ds='2020-08-10' and uid is not null
優(yōu)化后:
select count(a.uid) from (select uid from test where uid is not null and ds = '2020-08-10' group by uid) a
3.9 使用with as
拖慢hive查詢效率出了join產(chǎn)生的shuffle以外,還有一個(gè)就是子查詢,在SQL語句里面盡量減少子查詢。with as是將語句中用到的子查詢事先提取出來(類似臨時(shí)表),使整個(gè)查詢當(dāng)中的所有模塊都可以調(diào)用該查詢結(jié)果。使用with as可以避免Hive對不同部分的相同子查詢進(jìn)行重復(fù)計(jì)算。
優(yōu)化案例
優(yōu)化前:
select a.* from test1 a left join test2 b on a.uid = b.uid where a.ds='2020-08-10' and b.ds='2020-08-10'
優(yōu)化后:
with b as select uid from test2 where ds = '2020-08-10' and uid is not null select a.* from test1 a left join b on a.uid = b.uid where a.ds='2020-08-10' and a.uid is not null
3.10 大表Join小表
在編寫具有Join操作的查詢語句時(shí),有一項(xiàng)重要的原則需要遵循:應(yīng)當(dāng)將記錄較少的表或子查詢放置在Join操作符的左側(cè)。這樣做有助于減少數(shù)據(jù)量,提高查詢效率,并有效降低內(nèi)存溢出錯(cuò)誤的發(fā)生概率。
如果未指定MapJoin,或者不符合MapJoin的條件,Hive解析器將會將Join操作轉(zhuǎn)換成Common Join。這意味著Join操作將在Reduce階段完成,由此可能導(dǎo)致數(shù)據(jù)傾斜的問題。為了避免這種情況,可以通過使用MapJoin將小表完全加載到內(nèi)存中,并在Map端執(zhí)行Join操作,從而避免將Join操作留給Reducer階段處理。這種策略有效地減少了數(shù)據(jù)傾斜的風(fēng)險(xiǎn)。
優(yōu)化案例
--設(shè)置自動(dòng)選擇Mapjoin
set hive.auto.convert.join = true; 默認(rèn)為true
--大表小表的閾值設(shè)置(默認(rèn)25M以下認(rèn)為是小表):
set hive.mapjoin.smalltable.filesize=25000000;
3.11 大表Join大表
3.11.1 空key過濾
有時(shí)候,連接操作超時(shí)可能是因?yàn)槟承﹌ey對應(yīng)的數(shù)據(jù)量過大。相同key的數(shù)據(jù)被發(fā)送到相同的reducer上,由此導(dǎo)致內(nèi)存不足。在這種情況下,我們需要仔細(xì)分析這些異常的key。通常,這些key對應(yīng)的數(shù)據(jù)可能是異常的,因此我們需要在SQL語句中進(jìn)行適當(dāng)?shù)倪^濾。
3.11.2 空key轉(zhuǎn)換
當(dāng)某個(gè)key為空時(shí),盡管對應(yīng)的數(shù)據(jù)很豐富,但并非異常情況。在執(zhí)行join操作時(shí),這些數(shù)據(jù)必須包含在結(jié)果集中。為實(shí)現(xiàn)這一目的,可以考慮將表a中那些key為空的字段賦予隨機(jī)值,以確保數(shù)據(jù)能夠均勻、隨機(jī)地分布到不同的reducer上。
3.12 避免笛卡爾積
在執(zhí)行join操作時(shí),若不添加有效的on條件或者使用無效的on條件,而是采用where條件,可能會面臨關(guān)聯(lián)列包含大量空值或者重復(fù)值的情況。這可能導(dǎo)致Hive只能使用一個(gè)reducer來完成操作,從而引發(fā)笛卡爾積和數(shù)據(jù)膨脹問題。因此,在進(jìn)行join時(shí),務(wù)必注意確保使用有效的關(guān)聯(lián)條件,以免由于數(shù)據(jù)的空值或重復(fù)值而影響操作性能。
優(yōu)化案例
優(yōu)化前:
SELECT * FROM A, B;
--在優(yōu)化前的SQL代碼中,使用了隱式的內(nèi)連接(JOIN),沒有明確指定連接條件,導(dǎo)致產(chǎn)生了笛卡爾積
優(yōu)化后;
SELECT * FROM A CROSS JOIN B;
在優(yōu)化后的SQL代碼中,使用了明確的交叉連接(CROSS JOIN),確保只返回A和B表中的所有組合,而不會產(chǎn)生重復(fù)的行。 通過明確指定連接方式,可以避免不必要的笛卡爾積操作,提高查詢效率。
4. 數(shù)據(jù)加載和轉(zhuǎn)換
4.1 使用壓縮格式
在數(shù)據(jù)加載過程中,選擇合適的數(shù)據(jù)存儲格式(對于結(jié)構(gòu)化數(shù)據(jù),可以選擇Parquet或ORC等列式存儲格式;對于非結(jié)構(gòu)化數(shù)據(jù),可以選擇TextFile或SequenceFile等格式),可以提高查詢性能和減少存儲空間。
優(yōu)化案例
優(yōu)化前:
LOAD DATA INPATH '/path/to/data' INTO TABLE table;
優(yōu)化后:
LOAD DATA INPATH '/path/to/data' INTO TABLE table STORED AS ORC;
4.2 數(shù)據(jù)轉(zhuǎn)換和過濾
在數(shù)據(jù)加載之前,對數(shù)據(jù)進(jìn)行轉(zhuǎn)換和過濾可以減小數(shù)據(jù)量,并加快查詢速度。例如,可以使用Hive內(nèi)置函數(shù)對數(shù)據(jù)進(jìn)行清洗和轉(zhuǎn)換,以滿足特定的查詢需求。
優(yōu)化案例
優(yōu)化前:
SELECT * FROM table WHERE name LIKE '%John%';
優(yōu)化后:
SELECT * FROM table WHERE name = 'John';
4.3 多次INSERT單次掃描表
默認(rèn)情況下,Hive會執(zhí)行多次表掃描。因此,如果要在某張hive表中執(zhí)行多個(gè)操作,建議使用一次掃描并使用該掃描來執(zhí)行多個(gè)操作。
比如將一張表的數(shù)據(jù)多次查詢出來裝載到另外一張表中。如下面的示例,表my_table是一個(gè)分區(qū)表,分區(qū)字段為dt,如果需要在表中查詢2個(gè)特定的分區(qū)日期數(shù)據(jù),并將記錄裝載到2個(gè)不同的表中。
INSERT INTO temp_table_20201115 SELECT * FROM my_table WHERE dt ='2020-11-15'; INSERT INTO temp_table_20201116 SELECT * FROM my_table WHERE dt ='2020-11-16';
在以上查詢中,Hive將掃描表2次,為了避免這種情況,我們可以使用下面的方式:
FROM my_table INSERT INTO temp_table_20201115 SELECT * WHERE dt ='2020-11-15' INSERT INTO temp_table_20201116 SELECT * WHERE dt ='2020-11-16'
這樣可以確保只對my_table表執(zhí)行一次掃描,從而可以大大減少執(zhí)行的時(shí)間和資源。
5. 性能評估和優(yōu)化
5.1 使用EXPLAIN命令
使用EXPLAIN命令可以分析查詢計(jì)劃并評估查詢的性能。通過查看查詢計(jì)劃中的資源消耗情況,可以找出潛在的性能問題,并進(jìn)行相應(yīng)的優(yōu)化。
優(yōu)化案例
優(yōu)化前:
EXPLAIN SELECT * FROM table WHERE age = 30;
優(yōu)化后:
EXPLAIN SELECT * FROM table WHERE age = 30 AND partition = 'partition1';
5.2 調(diào)整并行度和資源配置
根據(jù)集群的配置和資源情況,合理調(diào)整Hive查詢的并行度和資源分配,可以提高查詢的并發(fā)性和整體性能。通過設(shè)置參數(shù)hive.exec.parallel值為true,就可以開啟并發(fā)執(zhí)行。不過,在共享集群中,需要注意下,如果job中并行階段增多,那么集群利用率就會增加。建議在數(shù)據(jù)量大,sql很長的時(shí)候使用,數(shù)據(jù)量小,sql比較的小開啟有可能還不如之前快。
優(yōu)化案例
優(yōu)化前:
SET hive.exec.parallel=true;
優(yōu)化后:
SET hive.exec.parallel=false; SET hive.exec.reducers.max=10;
6. 數(shù)據(jù)傾斜
任務(wù)進(jìn)度長時(shí)間維持在99%(或100%),檢查任務(wù)監(jiān)控頁面后發(fā)現(xiàn)僅有少量(1個(gè)或幾個(gè))reduce子任務(wù)未完成。這些未完成的reduce子任務(wù)由于處理的數(shù)據(jù)量與其他reduce子任務(wù)存在顯著差異。具體而言,單一reduce子任務(wù)的記錄數(shù)與平均記錄數(shù)之間存在顯著差異,通常可達(dá)到3倍甚至更多。此外,未完成的reduce子任務(wù)的最長時(shí)長明顯超過了平均時(shí)長。主要原因可以歸結(jié)為以下幾種:
6.1 空值引發(fā)的數(shù)據(jù)傾斜
在數(shù)據(jù)倉庫中存在大量空值(NULL)的情況下,導(dǎo)致數(shù)據(jù)分布不均勻的現(xiàn)象。這種數(shù)據(jù)傾斜可能會對數(shù)據(jù)分析和計(jì)算產(chǎn)生負(fù)面影響。當(dāng)數(shù)據(jù)倉庫中某個(gè)字段存在大量空值時(shí),這些空值會在數(shù)據(jù)計(jì)算和聚合操作中引起不平衡的情況。例如,在使用聚合函數(shù)(如SUM、COUNT、AVG等)對該字段進(jìn)行計(jì)算時(shí),空值并不會被包括在內(nèi),導(dǎo)致計(jì)算結(jié)果與實(shí)際情況不符。數(shù)據(jù)傾斜會導(dǎo)致部分reduce子任務(wù)負(fù)載過重,而其他reduce子任務(wù)負(fù)載較輕,從而影響任務(wù)的整體性能。這可能導(dǎo)致任務(wù)進(jìn)度長時(shí)間維持在99%(或100%),但仍有少量reduce子任務(wù)未完成的情況。
優(yōu)化方案
第一種:可以直接不讓null值參與join操作,即不讓null值有shuffle階段。
第二種:因?yàn)閚ull值參與shuffle時(shí)的hash結(jié)果是一樣的,那么我們可以給null值隨機(jī)賦值,這樣它們的hash結(jié)果就不一樣,就會進(jìn)到不同的reduce中。
6.2 不同數(shù)據(jù)類型引發(fā)的數(shù)據(jù)傾斜
在數(shù)據(jù)倉庫中,不同數(shù)據(jù)類型的字段可能具有不同的取值范圍和分布情況。例如,某個(gè)字段可能是枚舉類型,只有幾個(gè)固定的取值;而另一個(gè)字段可能是連續(xù)型數(shù)值,取值范圍較大。當(dāng)進(jìn)行數(shù)據(jù)計(jì)算和聚合操作時(shí),如果不同數(shù)據(jù)類型的字段在數(shù)據(jù)分布上存在明顯的差異,就會導(dǎo)致數(shù)據(jù)傾斜。數(shù)據(jù)傾斜會導(dǎo)致部分reduce子任務(wù)負(fù)載過重,而其他reduce子任務(wù)負(fù)載較輕,從而影響任務(wù)的整體性能。這可能導(dǎo)致任務(wù)進(jìn)度長時(shí)間維持在99%(或100%),但仍有少量reduce子任務(wù)未完成的情況。
優(yōu)化方案
如果key字段既有string類型也有int類型,默認(rèn)的hash就都會按int類型來分配,那我們直接把int類型都轉(zhuǎn)為string就好了,這樣key字段都為string,hash時(shí)就按照string類型分配了。
6.3 不可拆分大文件引發(fā)的數(shù)據(jù)傾斜
在Hadoop分布式計(jì)算框架中,數(shù)據(jù)通常會被切分成多個(gè)數(shù)據(jù)塊進(jìn)行并行處理。然而,當(dāng)遇到一些無法被切分的大文件時(shí),這些大文件會被作為一個(gè)整體分配給一個(gè)reduce任務(wù)進(jìn)行處理,而其他reduce任務(wù)則可能得到較小的數(shù)據(jù)量。這導(dǎo)致部分reduce任務(wù)負(fù)載過重,而其他任務(wù)負(fù)載較輕,從而影響任務(wù)的整體性能。
優(yōu)化方案
這種數(shù)據(jù)傾斜問題沒有什么好的解決方案,只能將使用GZIP壓縮等不支持文件分割的文件轉(zhuǎn)為bzip和zip等支持文件分割的壓縮方式。
所以,我們在對文件進(jìn)行壓縮時(shí),為避免因不可拆分大文件而引發(fā)數(shù)據(jù)讀取的傾斜,在數(shù)據(jù)壓縮的時(shí)候可以采用bzip2和Zip等支持文件分割的壓縮算法。
6.4 數(shù)據(jù)膨脹引發(fā)的數(shù)據(jù)傾斜
數(shù)據(jù)膨脹通常是由于某些數(shù)據(jù)在倉庫中存在大量冗余、重復(fù)或者拆分產(chǎn)生的。當(dāng)這些數(shù)據(jù)被用于計(jì)算和聚合操作時(shí),會導(dǎo)致部分reduce子任務(wù)負(fù)載過重,而其他reduce子任務(wù)負(fù)載較輕,從而影響任務(wù)的整體性能。
優(yōu)化方案
在Hive中可以通過參數(shù) hive.new.job.grouping.set.cardinality 配置的方式自動(dòng)控制作業(yè)的拆解,該參數(shù)默認(rèn)值是30。表示針對grouping sets/rollups/cubes這類多維聚合的操作,如果最后拆解的鍵組合大于該值,會啟用新的任務(wù)去處理大于該值之外的組合。如果在處理數(shù)據(jù)時(shí),某個(gè)分組聚合的列有較大的傾斜,可以適當(dāng)調(diào)小該值。
6.5 表連接時(shí)引發(fā)的數(shù)據(jù)傾斜
在數(shù)據(jù)倉庫中,表連接是常用的操作,用于將不同表中的數(shù)據(jù)進(jìn)行關(guān)聯(lián)和合并。然而,當(dāng)連接鍵在不同表中的數(shù)據(jù)分布不均勻時(shí),就會導(dǎo)致連接結(jié)果中某些連接鍵對應(yīng)的數(shù)據(jù)量遠(yuǎn)大于其他連接鍵的數(shù)據(jù)量。這會導(dǎo)致部分reduce任務(wù)負(fù)載過重,而其他任務(wù)負(fù)載較輕,從而影響任務(wù)的整體性能。
優(yōu)化方案
通常做法是將傾斜的數(shù)據(jù)存到分布式緩存中,分發(fā)到各個(gè)Map任務(wù)所在節(jié)點(diǎn)。在Map階段完成join操作,即MapJoin,這避免了 Shuffle,從而避免了數(shù)據(jù)傾斜。
6.6 確實(shí)無法減少數(shù)據(jù)量引發(fā)的數(shù)據(jù)傾斜
在某些情況下,數(shù)據(jù)的數(shù)量本身就非常龐大,例如某些業(yè)務(wù)場景中的大數(shù)據(jù)集,或者歷史數(shù)據(jù)的積累等。在這種情況下,即使采取了數(shù)據(jù)預(yù)處理、數(shù)據(jù)分區(qū)等措施,也無法減少數(shù)據(jù)的數(shù)量。
優(yōu)化方案
這類問題最直接的方式就是調(diào)整reduce所執(zhí)行的內(nèi)存大小。
調(diào)整reduce的內(nèi)存大小使用mapreduce.reduce.memory.mb這個(gè)配置。
7. 合并小文件
在HDFS中,每個(gè)小文件對象約占150字節(jié)的元數(shù)據(jù)空間,如果有大量的小文件存在,將會占用大量的內(nèi)存資源。這將嚴(yán)重限制NameNode節(jié)點(diǎn)的內(nèi)存容量,進(jìn)而影響整個(gè)集群的擴(kuò)展能力。從Hive的角度來看,小文件會導(dǎo)致產(chǎn)生大量的Map任務(wù),每個(gè)Map任務(wù)都需要啟動(dòng)一個(gè)獨(dú)立的JVM來執(zhí)行。這些任務(wù)的初始化、啟動(dòng)和執(zhí)行會消耗大量的計(jì)算資源,嚴(yán)重影響性能,因?yàn)槊總€(gè)小文件都需要進(jìn)行一次磁盤IO操作。
因此,我強(qiáng)烈建議避免使用包含大量小文件的數(shù)據(jù)源。相反,我們應(yīng)該進(jìn)行小文件合并操作,以減少查詢過程中的磁盤IO次數(shù),從而提高查詢效率。通過合并小文件,我們可以將多個(gè)小文件合并成一個(gè)較大的文件,從而減少對磁盤的IO訪問次數(shù)。這樣可以降低系統(tǒng)資源的消耗,提高查詢性能。
因此,在構(gòu)建數(shù)據(jù)倉庫時(shí),應(yīng)該盡可能使用較大的文件來存儲數(shù)據(jù),避免大量小文件的產(chǎn)生。如果已經(jīng)存在大量小文件,可以考慮進(jìn)行小文件合并操作,以優(yōu)化數(shù)據(jù)存儲和查詢性能。這樣可以提高Hive查詢的效率,減少資源的浪費(fèi),并保證系統(tǒng)的穩(wěn)定性和可擴(kuò)展性。
7.1 Hive引擎合并小文件參數(shù)
--是否和并Map輸出文件,默認(rèn)true
set hive.merge.mapfiles = true;
--是否合并 Reduce 輸出文件,默認(rèn)false
set hive.merge.mapredfiles = true;
--合并文件的大小,默認(rèn)256000000字節(jié)
set hive.merge.size.per.task = 256000000;
--當(dāng)輸出文件的平均大小小于該值時(shí),啟動(dòng)一個(gè)獨(dú)立的map-reduce任務(wù)進(jìn)行文件merge,默認(rèn)16000000字節(jié)
set hive.merge.smallfiles.avgsize = 256000000;
7.2 Spark引擎合并小文件參數(shù),所以盡量將MR切換成Spark
--是否合并小文件,默認(rèn)true
conf spark.sql.hive.mergeFiles=true;
8. 結(jié)論
本論文介紹了大數(shù)據(jù)從業(yè)者必備的Hive SQL調(diào)優(yōu)技巧,包括查詢優(yōu)化、數(shù)據(jù)分區(qū)和索引、數(shù)據(jù)加載和轉(zhuǎn)換等方面。通過深入理解Hive SQL語言和優(yōu)化策略,開發(fā)人員可以提升查詢效率和性能。通過優(yōu)化案例和優(yōu)化前后的SQL代碼,展示了每種優(yōu)化方案的實(shí)際應(yīng)用效果。
附:實(shí)踐案例
一、背景
某公司的線上平臺每天產(chǎn)生大量的用戶數(shù)據(jù),包括用戶行為、訂單信息等。為了更好地分析用戶行為和業(yè)務(wù)趨勢,我們需要對數(shù)據(jù)進(jìn)行復(fù)雜的查詢操作。原始的Hive SQL語句在執(zhí)行時(shí)存在性能瓶頸,因此我們決定對其進(jìn)行優(yōu)化。
二、原始SQL語句
原始的Hive SQL語句如下:
SELECT * FROM user_data WHERE user_id IN (SELECT user_id FROM order_data WHERE order_date >= '2022-01-01')
這個(gè)查詢語句的目的是從user_data表中選取所有在order_data表中最近一個(gè)月有訂單的用戶數(shù)據(jù)。由于user_data表和order_data表的數(shù)據(jù)量都很大,這個(gè)查詢語句執(zhí)行時(shí)間較長,存在性能瓶頸。
三、優(yōu)化策略
針對原始SQL語句的性能瓶頸,我們采取了以下優(yōu)化策略:
使用Spark計(jì)算引擎:Spark是一種高效的分布式計(jì)算框架,可以與Hive SQL集成使用來提高查詢效率。我們將使用Spark計(jì)算引擎來執(zhí)行查詢。
使用JOIN操作:將兩個(gè)表通過JOIN操作連接起來,可以減少數(shù)據(jù)的傳輸和計(jì)算開銷。我們將使用JOIN操作來連接user_data表和order_data表。
使用過濾條件:在查詢過程中,使用過濾條件可以減少數(shù)據(jù)的處理量。我們將使用過濾條件來篩選出符合條件的用戶數(shù)據(jù)。
四、優(yōu)化后的SQL語句
基于上述優(yōu)化策略,我們優(yōu)化后的Hive SQL語句如下:
SELECT u.* FROM user_data u JOIN (SELECT user_id FROM order_data WHERE order_date >= '2022-01-01') o ON u.user_id = o.user_id
這個(gè)查詢語句使用了JOIN操作將user_data表和子查詢結(jié)果連接起來,并通過過濾條件篩選出符合條件的用戶數(shù)據(jù)。同時(shí),我們使用了Spark計(jì)算引擎來執(zhí)行查詢。
五、性能對比
我們對優(yōu)化前后的SQL語句進(jìn)行了性能對比。以下是性能對比的結(jié)果:
執(zhí)行時(shí)間:優(yōu)化后的SQL語句執(zhí)行時(shí)間比原始SQL語句減少了約50%。
數(shù)據(jù)傳輸量:優(yōu)化后的SQL語句減少了數(shù)據(jù)的傳輸量,提高了數(shù)據(jù)處理的效率。
內(nèi)存消耗:優(yōu)化后的SQL語句使用了Spark計(jì)算引擎,可以更好地利用內(nèi)存資源,提高了查詢性能。
通過對比可以看出,優(yōu)化后的SQL語句在執(zhí)行時(shí)間、數(shù)據(jù)傳輸量和內(nèi)存消耗等方面都取得了顯著的提升。
審核編輯 黃宇
-
SQL
+關(guān)注
關(guān)注
1文章
775瀏覽量
44262 -
大數(shù)據(jù)
+關(guān)注
關(guān)注
64文章
8909瀏覽量
137821
發(fā)布評論請先 登錄
相關(guān)推薦
xgboost超參數(shù)調(diào)優(yōu)技巧 xgboost在圖像分類中的應(yīng)用
MCF8316A調(diào)優(yōu)指南
![MCF8316A<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>指南](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
SQL與NoSQL的區(qū)別
MCT8316A調(diào)優(yōu)指南
![MCT8316A<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>指南](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
MCT8315A調(diào)優(yōu)指南
![MCT8315A<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>指南](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
MMC DLL調(diào)優(yōu)
![MMC DLL<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
TDA3xx ISS調(diào)優(yōu)和調(diào)試基礎(chǔ)設(shè)施
![TDA3xx ISS<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>和調(diào)試基礎(chǔ)設(shè)施](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
智能調(diào)優(yōu),使步進(jìn)電機(jī)安靜而高效地運(yùn)行
![智能<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>,使步進(jìn)電機(jī)安靜而高效地運(yùn)行](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
MMC SW調(diào)優(yōu)算法
![MMC SW<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>算法](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
TAS58xx系列通用調(diào)優(yōu)指南
![TAS58xx系列通用<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>指南](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
AM6xA ISP調(diào)優(yōu)指南
![AM6xA ISP<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>指南](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
OSPI控制器PHY調(diào)優(yōu)算法
![OSPI控制器PHY<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>算法](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
正崴集團(tuán)與優(yōu)必達(dá)合資建立臺灣首座大型運(yùn)算中心
深度解析JVM調(diào)優(yōu)實(shí)踐應(yīng)用
![深度解析JVM<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>實(shí)踐應(yīng)用](https://file1.elecfans.com/web2/M00/C7/60/wKgaomYKG7iAYFw_AABHqg4LGBY228.png)
鴻蒙開發(fā)實(shí)戰(zhàn):【性能調(diào)優(yōu)組件】
![鴻蒙開發(fā)實(shí)戰(zhàn):【性能<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>組件】](https://file1.elecfans.com/web2/M00/C5/11/wKgaomXxTICAJTILAABJ7piMlD0583.jpg)
評論