Presto查詢優(yōu)化

我的CSDN: http://blog.csdn.net/FreeFishLy/article/details/79081764
Presto是一個(gè)開源的分布式SQL查詢引擎嘲更,適用于交互式分析查詢壹堰,數(shù)據(jù)量支持GB到PB字節(jié)。查詢語言是類ANSI SQL語句。筆者在多個(gè)項(xiàng)目中用到Presto做即席查詢,總結(jié)了一些優(yōu)化措施凹炸。


一土浸、數(shù)據(jù)存儲(chǔ)

  1. 合理設(shè)置分區(qū)
    與Hive類似,Presto會(huì)根據(jù)元信息讀取分區(qū)數(shù)據(jù)蕾殴,合理的分區(qū)能減少Presto數(shù)據(jù)讀取量笑撞,提升查詢性能。
  2. 使用列式存儲(chǔ)
    Presto對(duì)ORC文件讀取做了特定優(yōu)化钓觉,因此在Hive中創(chuàng)建Presto使用的表時(shí)茴肥,建議采用ORC格式存儲(chǔ)。相對(duì)于Parquet荡灾,Presto對(duì)ORC支持更好瓤狐。
  3. 使用壓縮
    數(shù)據(jù)壓縮可以減少節(jié)點(diǎn)間數(shù)據(jù)傳輸對(duì)IO帶寬壓力瞬铸,對(duì)于即席查詢需要快速解壓,建議采用snappy壓縮
  4. 預(yù)先排序
    對(duì)于已經(jīng)排序的數(shù)據(jù)础锐,在查詢的數(shù)據(jù)過濾階段嗓节,ORC格式支持跳過讀取不必要的數(shù)據(jù)。比如對(duì)于經(jīng)常需要過濾的字段可以預(yù)先排序皆警。
INSERT INTO table nation_orc partition(p) SELECT * FROM nation SORT BY n_name;

如果需要過濾n_name字段拦宣,則性能將提升。

SELECT count(*) FROM nation_orc WHERE n_name=’AUSTRALIA’;

二信姓、查詢SQL優(yōu)化

  1. 只選擇使用必要的字段
    由于采用列式存儲(chǔ)鸵隧,選擇需要的字段可加快字段的讀取、減少數(shù)據(jù)量意推。避免采用*讀取所有字段豆瘫。
[GOOD]: SELECT time,user,host FROM tbl
[BAD]:  SELECT * FROM tbl
  1. 過濾條件必須加上分區(qū)字段
    對(duì)于有分區(qū)的表,where語句中優(yōu)先使用分區(qū)字段進(jìn)行過濾菊值。acct_day是分區(qū)字段靡羡,visit_time是具體訪問時(shí)間
[GOOD]: SELECT time,user,host FROM tbl where acct_day=20171101
[BAD]:  SELECT * FROM tbl where visit_time=20171101
  1. Group By語句優(yōu)化
    合理安排Group by語句中字段順序?qū)π阅苡幸欢ㄌ嵘roup By語句中字段按照每個(gè)字段distinct數(shù)據(jù)多少進(jìn)行降序排列俊性。示例中uid是用戶id略步,比性別數(shù)據(jù)大很多。
[GOOD]: SELECT GROUP BY uid, gender
[BAD]:  SELECT GROUP BY gender, uid
  1. Order by時(shí)使用Limit
    Order by需要掃描數(shù)據(jù)到單個(gè)worker節(jié)點(diǎn)進(jìn)行排序定页,導(dǎo)致單個(gè)worker需要大量?jī)?nèi)存趟薄。如果是查詢Top N或者Bottom N,使用limit可減少排序計(jì)算和內(nèi)存壓力典徊。
[GOOD]: SELECT * FROM tbl ORDER BY time LIMIT 100
[BAD]:  SELECT * FROM tbl ORDER BY time

還有盡量將排序的字段減少些能加快計(jì)算杭煎。

  1. 使用近似聚合函數(shù)
    Presto有一些近似聚合函數(shù),對(duì)于允許有少量誤差的查詢場(chǎng)景卒落,使用這些函數(shù)對(duì)查詢性能有大幅提升羡铲。比如使用approx_distinct() 函數(shù)比Count(distinct x)有大概2.3%的誤差。
SELECT approx_distinct(user_id) FROM access

如果非要精確去重儡毕,請(qǐng)用Count+Group 語句代替

  1. 用regexp_like代替多個(gè)like語句
    Presto查詢優(yōu)化器沒有對(duì)多個(gè)like語句進(jìn)行優(yōu)化也切,使用regexp_like對(duì)性能有較大提升
[GOOD]
SELECT
  ...
FROM
  access
WHERE
  regexp_like(method, 'GET|POST|PUT|DELETE')
  
[BAD]
SELECT
  ...
FROM
  access
WHERE
  method LIKE '%GET%' OR
  method LIKE '%POST%' OR
  method LIKE '%PUT%' OR
  method LIKE '%DELETE%'
  1. 使用Join語句時(shí)將大表放在左邊
    Presto中join的默認(rèn)算法是broadcast join,即將join左邊的表分割到多個(gè)worker腰湾,然后將join右邊的表數(shù)據(jù)整個(gè)復(fù)制一份發(fā)送到每個(gè)worker進(jìn)行計(jì)算雷恃。如果右邊的表數(shù)據(jù)量太大,則可能會(huì)報(bào)內(nèi)存溢出錯(cuò)誤费坊。
[GOOD] SELECT ... FROM large_table l join small_table s on l.id = s.id
[BAD] SELECT ... FROM small_table s join large_table l on l.id = s.id

如果左表和右表都比較大怎么辦?為了防止內(nèi)存報(bào)錯(cuò)
1)修改配置distributed-joins-enabled (presto version >=0.196)
2)在每次查詢開始使用distributed_join的session選項(xiàng)

-- set session distributed_join = 'true'
SELECT ... FROM large_table1 join large_table2
on large_table1.id = large_table2.id

核心點(diǎn)就是使用distributed join. Presto的這種配置類型會(huì)將左表和右表同時(shí)以join key的hash value為分區(qū)字段進(jìn)行分區(qū). 所以即使右表也是大表,也會(huì)被拆分.
缺點(diǎn)是會(huì)增加很多網(wǎng)絡(luò)數(shù)據(jù)傳輸, 所以會(huì)比broadcast join的效率慢.

  1. 使用Rank函數(shù)代替row_number函數(shù)來獲取Top N
    在進(jìn)行一些分組排序場(chǎng)景時(shí)倒槐,使用rank函數(shù)性能更好
[GOOD]
SELECT checksum(rnk)
FROM (
  SELECT rank() OVER (PARTITION BY l_orderkey, l_partkey ORDER BY l_shipdate DESC) AS rnk
  FROM lineitem
) t
WHERE rnk = 1

[BAD]
SELECT checksum(rnk)
FROM (
  SELECT row_number() OVER (PARTITION BY l_orderkey, l_partkey ORDER BY l_shipdate DESC) AS rnk
  FROM lineitem
) t
WHERE rnk = 1

9.多用with語句
使用Presto分析統(tǒng)計(jì)數(shù)據(jù)時(shí),可考慮把多次查詢合并為一次查詢附井,用Presto提供的子查詢完成讨越。
這點(diǎn)和我們熟知的MySQL的使用不是很一樣两残。注意下列子查詢中的逗號(hào)。

WITH subquery_1 AS (
    SELECT a1, a2, a3 
    FROM Table_1 
    WHERE a3 between 20180101 and 20180131
),              
subquery_2 AS (
    SELECT b1, b2, b3
    FROM Table_2
    WHERE b3 between 20180101 and 20180131
)               
SELECT 
    subquery_1.a1, subquery_1.a2, 
    subquery_2.b1, subquery_2.b2
FROM subquery_1
    JOIN subquery_2
    ON subquery_1.a3 = subquery_2.b3; 
  1. 盡量用UNION ALL代替UNION
    和distinct的原因類似, UNION有去重的功能, 所以會(huì)引發(fā)內(nèi)存使用的問題.
    如果你只是拼接兩個(gè)或者多個(gè)SQL查詢的結(jié)果, 考慮用UNION ALL

三把跨、無縫替換Hive表

如果之前的hive表沒有用到ORC和snappy磕昼,那么怎么無縫替換而不影響線上的應(yīng)用:
比如如下一個(gè)hive表:

CREATE TABLE bdc_dm.res_category(
channel_id1 int comment '1級(jí)渠道id',
province string COMMENT '省',
city string comment '市', 
uv int comment 'uv'
)
comment 'example'
partitioned by (landing_date int COMMENT '日期:yyyymmdd')
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' COLLECTION ITEMS TERMINATED BY ',' MAP KEYS TERMINATED BY ':' LINES TERMINATED BY '\n';

建立對(duì)應(yīng)的orc表

CREATE TABLE bdc_dm.res_category_orc(
channel_id1 int comment '1級(jí)渠道id',
province string COMMENT '省',
city string comment '市', 
uv int comment 'uv'
)
comment 'example'
partitioned by (landing_date int COMMENT '日期:yyyymmdd')
row format delimited fields terminated by '\t'
stored as orc 
TBLPROPERTIES ("orc.compress"="SNAPPY");

先將數(shù)據(jù)灌入orc表,然后更換表名

insert overwrite table bdc_dm.res_category_orc partition(landing_date)
select * from bdc_dm.res_category where landing_date >= 20171001;

ALTER TABLE bdc_dm.res_category RENAME TO bdc_dm.res_category_tmp;
ALTER TABLE bdc_dm.res_category_orc RENAME TO bdc_dm.res_category;

其中res_category_tmp是一個(gè)備份表节猿,若線上運(yùn)行一段時(shí)間后沒有出現(xiàn)問題,則可以刪除該表漫雕。

四滨嘱、注意事項(xiàng)

  1. ORC和Parquet都支持列式存儲(chǔ),但是ORC對(duì)Presto支持更好(Parquet對(duì)Impala支持更好)
  2. 對(duì)于列式存儲(chǔ)而言浸间,存儲(chǔ)文件為二進(jìn)制的太雨,對(duì)于經(jīng)常增刪字段的表,建議不要使用列式存儲(chǔ)(修改文件元數(shù)據(jù)代價(jià)大)魁蒜。對(duì)比數(shù)據(jù)倉庫囊扳,dwd層建議不要使用ORC,而dm層則建議使用

若在使用Presto和Hive過程中有任何問題兜看,歡迎給我留言锥咸!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市细移,隨后出現(xiàn)的幾起案子搏予,更是在濱河造成了極大的恐慌,老刑警劉巖弧轧,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雪侥,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡精绎,警方通過查閱死者的電腦和手機(jī)速缨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來代乃,“玉大人旬牲,你說我怎么就攤上這事「橄牛” “怎么了引谜?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長擎浴。 經(jīng)常有香客問我员咽,道長,這世上最難降的妖魔是什么贮预? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任贝室,我火速辦了婚禮契讲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘滑频。我一直安慰自己捡偏,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布峡迷。 她就那樣靜靜地躺著银伟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪绘搞。 梳的紋絲不亂的頭發(fā)上彤避,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音夯辖,去河邊找鬼琉预。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蒿褂,可吹牛的內(nèi)容都是我干的圆米。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼啄栓,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼娄帖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起昙楚,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤块茁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后桂肌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體数焊,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年崎场,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了佩耳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谭跨,死狀恐怖干厚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情螃宙,我是刑警寧澤蛮瞄,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站谆扎,受9級(jí)特大地震影響挂捅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜堂湖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一闲先、第九天 我趴在偏房一處隱蔽的房頂上張望状土。 院中可真熱鬧,春花似錦伺糠、人聲如沸蒙谓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽累驮。三九已至,卻和暖如春舵揭,著一層夾襖步出監(jiān)牢的瞬間谤专,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來泰國打工琉朽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人稚铣。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓箱叁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親惕医。 傳聞我的和親對(duì)象是個(gè)殘疾皇子耕漱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359