1 Fetch抓取
Fetch抓取是指淋袖,Hive中對(duì)某些情況的查詢可以不必使用MapReduce計(jì)算。例如:SELECT * FROM employees;在這種情況下锯梁,Hive可以簡單地讀取employee對(duì)應(yīng)的存儲(chǔ)目錄下的文件即碗,然后輸出查詢結(jié)果到控制臺(tái)焰情。
在hive-default.xml.template文件中hive.fetch.task.conversion默認(rèn)是more,老版本hive默認(rèn)是minimal剥懒,該屬性修改為more以后内舟,在全局查找、字段查找初橘、limit查找等都不走mapreduce验游。
<property>
<name>hive.fetch.task.conversion</name>
<value>more</value>
<description>
Expects one of [none, minimal, more].
Some select queries can be converted to single FETCH task minimizing latency.
Currently the query should be single sourced not having any subquery and should not have
any aggregations or distincts (which incurs RS), lateral views and joins.
0. none : disable hive.fetch.task.conversion
1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only
2. more : SELECT, FILTER, LIMIT only (support TABLESAMPLE and virtual columns)
</description>
</property>
hive (default)> set hive.fetch.task.conversion=more;
hive (default)> select * from emp;
hive (default)> select ename from emp;
hive (default)> select ename from emp limit 3;
2 本地模式
大多數(shù)的Hadoop Job是需要Hadoop提供的完整的可擴(kuò)展性來處理大數(shù)據(jù)集的。不過壁却,有時(shí)Hive的輸入數(shù)據(jù)量是非常小的批狱。在這種情況下,為查詢觸發(fā)執(zhí)行任務(wù)消耗的時(shí)間可能會(huì)比實(shí)際job的執(zhí)行時(shí)間要多的多展东。對(duì)于大多數(shù)這種情況赔硫,Hive可以通過本地模式在單臺(tái)機(jī)器上處理所有的任務(wù)。對(duì)于小數(shù)據(jù)集盐肃,執(zhí)行時(shí)間可以明顯被縮短爪膊。
用戶可以通過設(shè)置hive.exec.mode.local.auto的值為true,來讓Hive在適當(dāng)?shù)臅r(shí)候自動(dòng)啟動(dòng)這個(gè)優(yōu)化砸王。
set hive.exec.mode.local.auto=true; //開啟本地mr
//設(shè)置local mr的最大輸入數(shù)據(jù)量推盛,當(dāng)輸入數(shù)據(jù)量小于這個(gè)值時(shí)采用local mr的方式,默認(rèn)為134217728谦铃,即128M
set hive.exec.mode.local.auto.inputbytes.max=50000000;
//設(shè)置local mr的最大輸入文件個(gè)數(shù)耘成,當(dāng)輸入文件個(gè)數(shù)小于這個(gè)值時(shí)采用local mr的方式,默認(rèn)為4
set hive.exec.mode.local.auto.input.files.max=10;
-
開啟本地模式驹闰,并執(zhí)行查詢語句
hive (default)> set hive.exec.mode.local.auto=true; hive (default)> select * from emp cluster by deptno; Time taken: 1.328 seconds, Fetched: 14 row(s)
-
關(guān)閉本地模式瘪菌,并執(zhí)行查詢語句
hive (default)> set hive.exec.mode.local.auto=false; hive (default)> select * from emp cluster by deptno; Time taken: 20.09 seconds, Fetched: 14 row(s)
3 表的優(yōu)化
3.1 小表、大表Join
將key相對(duì)分散嘹朗,并且數(shù)據(jù)量小的表放在join的左邊师妙,這樣可以有效減少內(nèi)存溢出錯(cuò)誤發(fā)生的幾率;再進(jìn)一步屹培,可以使用map join讓小的維度表(1000條以下的記錄條數(shù))先進(jìn)內(nèi)存默穴。在map端完成reduce。
新版的hive已經(jīng)對(duì)小表JOIN大表和大表JOIN小表進(jìn)行了優(yōu)化褪秀。小表放在左邊和右邊已經(jīng)沒有明顯區(qū)別蓄诽。
3.2 大表Join大表
-
空KEY過濾
有時(shí)join超時(shí)是因?yàn)槟承﹌ey對(duì)應(yīng)的數(shù)據(jù)太多,而相同key對(duì)應(yīng)的數(shù)據(jù)都會(huì)發(fā)送到相同的reducer上媒吗,從而導(dǎo)致內(nèi)存不夠仑氛。此時(shí)我們應(yīng)該仔細(xì)分析這些異常的key,很多情況下蝴猪,這些key對(duì)應(yīng)的數(shù)據(jù)是異常數(shù)據(jù)调衰,我們需要在SQL語句中進(jìn)行過濾。例如key對(duì)應(yīng)的字段為空自阱,操作如下:
-
空key轉(zhuǎn)換
有時(shí)雖然某個(gè)key為空對(duì)應(yīng)的數(shù)據(jù)很多嚎莉,但是相應(yīng)的數(shù)據(jù)不是異常數(shù)據(jù),必須要包含在join的結(jié)果中沛豌,此時(shí)我們可以表a中key為空的字段賦一個(gè)隨機(jī)的值趋箩,使得數(shù)據(jù)隨機(jī)均勻地分不到不同的reducer上。
未隨機(jī)分布空null值
(1)設(shè)置5個(gè)reduce個(gè)數(shù)
set mapreduce.job.reduces = 5;
(2)JOIN兩張表
insert overwrite table jointable2 select n.* from nullidtable n left join ori b on n.id = b.id;
結(jié)果:出現(xiàn)了數(shù)據(jù)傾斜加派,某些reducer的資源消耗遠(yuǎn)大于其他reducer叫确。
隨機(jī)分布空null值
(1)設(shè)置5個(gè)reduce個(gè)數(shù)
set mapreduce.job.reduces = 5;
(2)JOIN兩張表
insert overwrite table jointable2 select n.* from nullidtable n full join ori o on case when n.id is null then concat('hive', rand()) else n.id end = o.id;
結(jié)果:消除了數(shù)據(jù)傾斜,負(fù)載均衡reducer的資源消耗
3.3 MapJoin
如果不指定MapJoin或者不符合MapJoin的條件芍锦,那么Hive解析器會(huì)將Join操作轉(zhuǎn)換成Common Join竹勉,即:在Reduce階段完成join。容易發(fā)生數(shù)據(jù)傾斜娄琉〈闻遥可以用MapJoin把小表全部加載到內(nèi)存在map端進(jìn)行join,避免reducer處理孽水。
-
開啟MapJoin參數(shù)設(shè)置
(1)設(shè)置自動(dòng)選擇Mapjoin
set hive.auto.convert.join = true; 默認(rèn)為true
(2)大表小表的閾值設(shè)置(默認(rèn)25M以下認(rèn)為是小表):
set hive.mapjoin.smalltable.filesize=25000000;
MapJoin工作機(jī)制
3.4 Group By
默認(rèn)情況下票腰,Map階段同一Key數(shù)據(jù)分發(fā)給一個(gè)reduce,當(dāng)一個(gè)key數(shù)據(jù)過大時(shí)就傾斜了女气。
并不是所有的聚合操作都需要在Reduce端完成杏慰,很多聚合操作都可以先在Map端進(jìn)行部分聚合,最后在Reduce端得出最終結(jié)果炼鞠。
-
開啟Map端聚合參數(shù)設(shè)置
(1)是否在Map端進(jìn)行聚合缘滥,默認(rèn)為True
hive.map.aggr = true
(2)在Map端進(jìn)行聚合操作的條目數(shù)目
hive.groupby.mapaggr.checkinterval = 100000
(3)有數(shù)據(jù)傾斜的時(shí)候進(jìn)行負(fù)載均衡(默認(rèn)是false)
hive.groupby.skewindata = true
當(dāng)選項(xiàng)設(shè)定為 true,生成的查詢計(jì)劃會(huì)有兩個(gè)MR Job簇搅。第一個(gè)MR Job中完域,Map的輸出結(jié)果會(huì)隨機(jī)分布到Reduce中,每個(gè)Reduce做部分聚合操作瘩将,并輸出結(jié)果吟税,這樣處理的結(jié)果是相同的Group By Key有可能被分發(fā)到不同的Reduce中,從而達(dá)到負(fù)載均衡的目的姿现;第二個(gè)MR Job再根據(jù)預(yù)處理的數(shù)據(jù)結(jié)果按照Group By Key分布到Reduce中(這個(gè)過程可以保證相同的Group By Key被分布到同一個(gè)Reduce中)肠仪,最后完成最終的聚合操作。
3.5 Count(Distinct) 去重統(tǒng)計(jì)
數(shù)據(jù)量小的時(shí)候無所謂备典,數(shù)據(jù)量大的情況下异旧,由于COUNT DISTINCT操作需要用一個(gè)Reduce Task來完成,這一個(gè)Reduce需要處理的數(shù)據(jù)量太大提佣,就會(huì)導(dǎo)致整個(gè)Job很難完成吮蛹,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替換:
采用GROUP by去重id
hive (default)> select count(distinct id) from bigtable;
hive (default)> select count(id) from (select id from bigtable group by id) a;
雖然會(huì)多用一個(gè)Job來完成荤崇,但在數(shù)據(jù)量大的情況下,這個(gè)絕對(duì)是值得的潮针。
3.6 笛卡爾積
盡量避免笛卡爾積术荤,join的時(shí)候不加on條件,或者無效的on條件每篷,Hive只能使用1個(gè)reducer來完成笛卡爾積瓣戚。
3.7 行列過濾
列處理:在SELECT中,只拿需要的列焦读,如果有子库,盡量使用分區(qū)過濾,少用SELECT *矗晃。
行處理:在分區(qū)剪裁中仑嗅,當(dāng)使用外關(guān)聯(lián)時(shí),如果將副表的過濾條件寫在Where后面喧兄,那么就會(huì)先全表關(guān)聯(lián)无畔,之后再過濾
3.8 動(dòng)態(tài)分區(qū)調(diào)整
關(guān)系型數(shù)據(jù)庫中,對(duì)分區(qū)表Insert數(shù)據(jù)時(shí)候吠冤,數(shù)據(jù)庫自動(dòng)會(huì)根據(jù)分區(qū)字段的值浑彰,將數(shù)據(jù)插入到相應(yīng)的分區(qū)中,Hive中也提供了類似的機(jī)制拯辙,即動(dòng)態(tài)分區(qū)(Dynamic Partition)郭变,只不過,使用Hive的動(dòng)態(tài)分區(qū)涯保,需要進(jìn)行相應(yīng)的配置诉濒。
-
開啟動(dòng)態(tài)分區(qū)參數(shù)設(shè)置
(1)開啟動(dòng)態(tài)分區(qū)功能(默認(rèn)true,開啟)
hive.exec.dynamic.partition=true
(2)設(shè)置為非嚴(yán)格模式(動(dòng)態(tài)分區(qū)的模式夕春,默認(rèn)strict未荒,表示必須指定至少一個(gè)分區(qū)為靜態(tài)分區(qū),nonstrict模式表示允許所有的分區(qū)字段都可以使用動(dòng)態(tài)分區(qū)及志。)
hive.exec.dynamic.partition.mode=nonstrict
(3)在所有執(zhí)行MR的節(jié)點(diǎn)上片排,最大一共可以創(chuàng)建多少個(gè)動(dòng)態(tài)分區(qū)。
hive.exec.max.dynamic.partitions=1000
(4)在每個(gè)執(zhí)行MR的節(jié)點(diǎn)上速侈,最大可以創(chuàng)建多少個(gè)動(dòng)態(tài)分區(qū)率寡。該參數(shù)需要根據(jù)實(shí)際的數(shù)據(jù)來設(shè)定。比如:源數(shù)據(jù)中包含了一年的數(shù)據(jù)倚搬,即day字段有365個(gè)值冶共,那么該參數(shù)就需要設(shè)置成大于365,如果使用默認(rèn)值100,則會(huì)報(bào)錯(cuò)捅僵。
hive.exec.max.dynamic.partitions.pernode=100
(5)整個(gè)MR Job中家卖,最大可以創(chuàng)建多少個(gè)HDFS文件。
hive.exec.max.created.files=100000
(6)當(dāng)有空分區(qū)生成時(shí)庙楚,是否拋出異常篡九。一般不需要設(shè)置。
hive.error.on.empty.partition=false
3.9 分桶
3.10 分區(qū)
4 數(shù)據(jù)傾斜
4.1 合理設(shè)置Map數(shù)
-
通常情況下醋奠,作業(yè)會(huì)通過input的目錄產(chǎn)生一個(gè)或者多個(gè)map任務(wù)
主要的決定因素有:input的文件總個(gè)數(shù),input的文件大小伊佃,集群設(shè)置的文件塊大小窜司。
-
是不是map數(shù)越多越好?
答案是否定的。如果一個(gè)任務(wù)有很多小文件(遠(yuǎn)遠(yuǎn)小于塊大小128m)航揉,則每個(gè)小文件也會(huì)被當(dāng)做一個(gè)塊塞祈,用一個(gè)map任務(wù)來完成,而一個(gè)map任務(wù)啟動(dòng)和初始化的時(shí)間遠(yuǎn)遠(yuǎn)大于邏輯處理的時(shí)間帅涂,就會(huì)造成很大的資源浪費(fèi)议薪。而且,同時(shí)可執(zhí)行的map數(shù)是受限的媳友。
-
是不是保證每個(gè)map處理接近128m的文件塊斯议,就高枕無憂了?
答案也是不一定。比如有一個(gè)127m的文件醇锚,正常會(huì)用一個(gè)map去完成哼御,但這個(gè)文件只有一個(gè)或者兩個(gè)小字段,卻有幾千萬的記錄焊唬,如果map處理的邏輯比較復(fù)雜恋昼,用一個(gè)map任務(wù)去做,肯定也比較耗時(shí)赶促。
? 針對(duì)上面的問題2和3液肌,采取兩種方式來解決:即減少map數(shù)和增加map數(shù);
4.2 小文件進(jìn)行合并
在map執(zhí)行前合并小文件鸥滨,減少map數(shù):CombineHiveInputFormat具有對(duì)小文件進(jìn)行合并的功能(系統(tǒng)默認(rèn)的格式)嗦哆。HiveInputFormat沒有對(duì)小文件合并功能。
set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
4.3 復(fù)雜文件增加Map數(shù)
當(dāng)input的文件都很大爵赵,任務(wù)邏輯復(fù)雜吝秕,map執(zhí)行非常慢的時(shí)候,可以考慮增加Map數(shù)空幻,來使得每個(gè)map處理的數(shù)據(jù)量減少烁峭,從而提高任務(wù)的執(zhí)行效率。
增加map的方法為:根據(jù)computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M公式,調(diào)整maxSize最大值约郁。讓maxSize最大值低于blocksize就可以增加map的個(gè)數(shù)缩挑。
4.4 合理設(shè)置Reduce數(shù)
-
調(diào)整reduce個(gè)數(shù)方法一
(1)每個(gè)Reduce處理的數(shù)據(jù)量默認(rèn)是256MB
hive.exec.reducers.bytes.per.reducer=256000000
(2)每個(gè)任務(wù)最大的reduce數(shù),默認(rèn)為1009
hive.exec.reducers.max=1009
(3)計(jì)算reducer數(shù)的公式
N=min(參數(shù)2鬓梅,總輸入數(shù)據(jù)量/參數(shù)1)
-
調(diào)整reduce個(gè)數(shù)方法二
在hadoop的mapred-default.xml文件中修改
設(shè)置每個(gè)job的Reduce個(gè)數(shù)
set mapreduce.job.reduces = 15;
-
reduce個(gè)數(shù)并不是越多越好
1)過多的啟動(dòng)和初始化reduce也會(huì)消耗時(shí)間和資源供置;
2)另外,有多少個(gè)reduce绽快,就會(huì)有多少個(gè)輸出文件芥丧,如果生成了很多個(gè)小文件,那么如果這些小文件作為下一個(gè)任務(wù)的輸入坊罢,則也會(huì)出現(xiàn)小文件過多的問題续担;
在設(shè)置reduce個(gè)數(shù)的時(shí)候也需要考慮這兩個(gè)原則:
? 處理大數(shù)據(jù)量利用合適的reduce數(shù);
? 使單個(gè)reduce任務(wù)處理數(shù)據(jù)量大小要合適活孩;
5 并行執(zhí)行
Hive會(huì)將一個(gè)查詢轉(zhuǎn)化成一個(gè)或者多個(gè)階段物遇。這樣的階段可以是MapReduce階段、抽樣階段憾儒、合并階段询兴、limit階段∑鹬海或者Hive執(zhí)行過程中可能需要的其他階段诗舰。默認(rèn)情況下,Hive一次只會(huì)執(zhí)行一個(gè)階段训裆。不過始衅,某個(gè)特定的job可能包含眾多的階段,而這些階段可能并非完全互相依賴的缭保,也就是說有些階段是可以并行執(zhí)行的汛闸,這樣可能使得整個(gè)job的執(zhí)行時(shí)間縮短。不過艺骂,如果有更多的階段可以并行執(zhí)行诸老,那么job可能就越快完成。
通過設(shè)置參數(shù)hive.exec.parallel值為true钳恕,就可以開啟并發(fā)執(zhí)行别伏。不過,在共享集群中忧额,需要注意下厘肮,如果job中并行階段增多,那么集群利用率就會(huì)增加睦番。
set hive.exec.parallel=true; //打開任務(wù)并行執(zhí)行
set hive.exec.parallel.thread.number=16; //同一個(gè)sql允許最大并行度类茂,默認(rèn)為8耍属。
當(dāng)然,得是在系統(tǒng)資源比較空閑的時(shí)候才有優(yōu)勢巩检,否則厚骗,沒資源,并行也起不來兢哭。
6 嚴(yán)格模式
Hive提供了一個(gè)嚴(yán)格模式领舰,可以防止用戶執(zhí)行那些可能意想不到的不好的影響的查詢。
通過設(shè)置屬性hive.mapred.mode值為默認(rèn)是非嚴(yán)格模式nonstrict 迟螺。開啟嚴(yán)格模式需要修改hive.mapred.mode值為strict
開啟嚴(yán)格模式可以禁止3種類型的查詢
<property>
<name>hive.mapred.mode</name>
<value>strict</value>
<description>
The mode in which the Hive operations are being performed.
In strict mode, some risky queries are not allowed to run. They include:
Cartesian Product.
No partition being picked up for a query.
Comparing bigints and strings.
Comparing bigints and doubles.
Orderby without limit.
</description>
</property>
- 對(duì)于分區(qū)表冲秽,除非where語句中含有分區(qū)字段過濾條件來限制范圍,否則不允許執(zhí)行矩父。換句話說劳跃,就是用戶不允許掃描所有分區(qū)。進(jìn)行這個(gè)限制的原因是浙垫,通常分區(qū)表都擁有非常大的數(shù)據(jù)集,而且數(shù)據(jù)增加迅速郑诺。沒有進(jìn)行分區(qū)限制的查詢可能會(huì)消耗令人不可接受的巨大資源來處理這個(gè)表夹姥。
- 對(duì)于使用了order by語句的查詢,要求必須使用limit語句辙诞。因?yàn)閛rder by為了執(zhí)行排序過程會(huì)將所有的結(jié)果數(shù)據(jù)分發(fā)到同一個(gè)Reducer中進(jìn)行處理辙售,強(qiáng)制要求用戶增加這個(gè)LIMIT語句可以防止Reducer額外執(zhí)行很長一段時(shí)間。
- 限制笛卡爾積的查詢飞涂。對(duì)關(guān)系型數(shù)據(jù)庫非常了解的用戶可能期望在執(zhí)行JOIN查詢的時(shí)候不使用ON語句而是使用where語句旦部,這樣關(guān)系數(shù)據(jù)庫的執(zhí)行優(yōu)化器就可以高效地將WHERE語句轉(zhuǎn)化成那個(gè)ON語句。不幸的是较店,Hive并不會(huì)執(zhí)行這種優(yōu)化士八,因此,如果表足夠大梁呈,那么這個(gè)查詢就會(huì)出現(xiàn)不可控的情況婚度。
7 JVM重用
JVM重用是Hadoop調(diào)優(yōu)參數(shù)的內(nèi)容,其對(duì)Hive的性能具有非常大的影響官卡,特別是對(duì)于很難避免小文件的場景或task特別多的場景蝗茁,這類場景大多數(shù)執(zhí)行時(shí)間都很短。
Hadoop的默認(rèn)配置通常是使用派生JVM來執(zhí)行map和Reduce任務(wù)的寻咒。這時(shí)JVM的啟動(dòng)過程可能會(huì)造成相當(dāng)大的開銷哮翘,尤其是執(zhí)行的job包含有成百上千task任務(wù)的情況。JVM重用可以使得JVM實(shí)例在同一個(gè)job中重新使用N次毛秘。N的值可以在Hadoop的mapred-site.xml文件中進(jìn)行配置饭寺。通常在10-20之間,具體多少需要根據(jù)具體業(yè)務(wù)場景測試得出。
<property>
<name>mapreduce.job.jvm.numtasks</name>
<value>10</value>
<description>How many tasks to run per jvm. If set to -1, there is no limit.
</description>
</property>
這個(gè)功能的缺點(diǎn)是佩研,開啟JVM重用將一直占用使用到的task插槽柑肴,以便進(jìn)行重用,直到任務(wù)完成后才能釋放旬薯。如果某個(gè)“不平衡的”job中有某幾個(gè)reduce task執(zhí)行的時(shí)間要比其他Reduce task消耗的時(shí)間多的多的話晰骑,那么保留的插槽就會(huì)一直空閑著卻無法被其他的job使用,直到所有的task都結(jié)束了才會(huì)釋放绊序。
8 推測執(zhí)行
在分布式集群環(huán)境下硕舆,因?yàn)槌绦駼ug(包括Hadoop本身的bug),負(fù)載不均衡或者資源分布不均等原因骤公,會(huì)造成同一個(gè)作業(yè)的多個(gè)任務(wù)之間運(yùn)行速度不一致抚官,有些任務(wù)的運(yùn)行速度可能明顯慢于其他任務(wù)(比如一個(gè)作業(yè)的某個(gè)任務(wù)進(jìn)度只有50%,而其他所有任務(wù)已經(jīng)運(yùn)行完畢)阶捆,則這些任務(wù)會(huì)拖慢作業(yè)的整體執(zhí)行進(jìn)度凌节。為了避免這種情況發(fā)生,Hadoop采用了推測執(zhí)行(Speculative Execution)機(jī)制洒试,它根據(jù)一定的法則推測出“拖后腿”的任務(wù)倍奢,并為這樣的任務(wù)啟動(dòng)一個(gè)備份任務(wù),讓該任務(wù)與原始任務(wù)同時(shí)處理同一份數(shù)據(jù)垒棋,并最終選用最先成功運(yùn)行完成任務(wù)的計(jì)算結(jié)果作為最終結(jié)果卒煞。
設(shè)置開啟推測執(zhí)行參數(shù):Hadoop的mapred-site.xml文件中進(jìn)行配置
<property>
<name>mapreduce.map.speculative</name>
<value>true</value>
<description>If true, then multiple instances of some map tasks may be executed in parallel.</description>
</property>
<property>
<name>mapreduce.reduce.speculative</name>
<value>true</value>
<description>If true, then multiple instances of some reduce tasks may be executed in parallel.</description>
</property>
hive本身也提供了配置項(xiàng)來控制reduce-side的推測執(zhí)行:
<property>
<name>hive.mapred.reduce.tasks.speculative.execution</name>
<value>true</value>
<description>Whether speculative execution for reducers should be turned on. </description>
</property>
關(guān)于調(diào)優(yōu)這些推測執(zhí)行變量,還很難給一個(gè)具體的建議叼架。如果用戶對(duì)于運(yùn)行時(shí)的偏差非常敏感的話畔裕,那么可以將這些功能關(guān)閉掉。如果用戶因?yàn)檩斎霐?shù)據(jù)量很大而需要執(zhí)行長時(shí)間的map或者Reduce task的話乖订,那么啟動(dòng)推測執(zhí)行造成的浪費(fèi)是非常巨大大扮饶。
9 壓縮
10 執(zhí)行計(jì)劃(Explain)
-
基本語法
EXPLAIN [EXTENDED | DEPENDENCY | AUTHORIZATION] query
-
案例實(shí)操
(1)查看下面這條語句的執(zhí)行計(jì)劃
hive (default)> explain select * from emp; hive (default)> explain select deptno, avg(sal) avg_sal from emp group by deptno;
(2)查看詳細(xì)執(zhí)行計(jì)劃
hive (default)> explain extended select * from emp; hive (default)> explain extended select deptno, avg(sal) avg_sal from emp group by deptno;