order by
与sort by
以及distribute by 配合sort by
和cluster by
的区别先记结论:
order by
: 全局排序,全局有序,无论数据量多大,只会有一个reducetask运行,所以当数据量比较大的时候,性能会大打折扣。(手动设置reducetask对其没有影响)
sort by
: 会根据数据量自动调整reducetask的个数的(hive2.x默认mapreduce.job.reduces值为-1),也可以手动设置个数,sort by是进行局部排序的,只有一个reducetask时,与order by一致,但是当数据量一大时会分成多个reducetask进行执行,性能是会大大提升的。但是只用 sort by
的话,相同数据是不会分到一起的,需要配合distribute by
一起使用。
distribute by 配合sort by
: distribute by
用于sort by
之前的分区字段的设置,两者配合,能够保证distribute by
后面的字段值相同的被分到同一个分区中。注意此种方式分区的字段和排序的字段可以不一致。即distribute by
后面与sort by
后面的字段可以不一样。
cluster by
: 相当于 distribute by 字段 sort by 字段,即分区字段和局部排序字段必须一样,而且必须是升序,限制比较大。
我们来看看reducetask的默认数量:
set mapreduce.job.reduces; # 默认 -1
hive 1.x默认是每一个mapreduce任务只有1
个reducetask,2.x默认为 -1
,即表示它的个数是根据实际的任务量大小动态分配的。(这里先为-1,后面改成3测试结果
)
hive> select * from class;
OK
tom 7512
tim 7512
kom 7514
kim 7512
jom 7511
jim 7511
lim 7514
rim 7512
sju 7512
tds 7512
jde 7511
jedw 7511
jsd 7514
xjs 7514
jsd 7514
ew 7514
jsew3d 7514
xjews 7514
jsew3d 7514
xjews 7514
je32 7511
lie23e 7514
riwedw 7512
sjdweu 7512
tdsdwe 7512
select * from class order by name desc;
测试结果数据如下:(只有开启1个reducetask)
xjs 7514
xjews 7514
xjews 7514
tom 7512
tim 7512
tdsdwe 7512
tds 7512
sju 7512
sjdweu 7512
riwedw 7512
rim 7512
lim 7514
lie23e 7514
kom 7514
kim 7512
jsew3d 7514
jsew3d 7514
jsd 7514
jsd 7514
jom 7511
jim 7511
jedw 7511
je32 7511
jde 7511
ew 7514
select * from class sort by name desc;
结果同上面order by 的输出一样,只运行了1个reducetask。至此,你以为sort by 与order by是一致的,那就大错特错了
。
下面我调整reducetask个数:
set mapreduce.job.reduces=3;
现在再测试一下order by:
select * from class order by name desc;
结果同上面一样,reducetask个数还是1,似乎没有影响,还是一样全局排序
。
select * from class sort by name desc;
xjews 7514
tdsdwe 7512
tds 7512
sju 7512
sjdweu 7512
rim 7512
lim 7514
lie23e 7514
jsew3d 7514
jsd 7514
jom 7511
jim 7511
xjs 7514
xjews 7514
tim 7512
kom 7514
kim 7512
jsew3d 7514
jedw 7511
jde 7511
tom 7512
riwedw 7512
jsd 7514
je32 7511
ew 7514
从上面数据看,这数据好乱啊,仔细看,我们会发现,上面我用空行隔开的数据内部是有序的,但是是为什么还有相同的数据在不同的部分中(分区中)呢?(xjews在第一部分中出现,在第二部分中也出现)
其实,sort by是做局部排序的,由于这里是3个reducetask,即对应3个mapreduce任务的分区,sort by 只是对着3个分区中的数据进行排序的。那么每个分区的数据是根据什么拿到的呢?实际上是随机的,然后对每一个分区中的数据进行排序输出,结果就如上面所示。
随意为了避免数据的随机拿取,我们需要让sort by
结合distribute by
使用,distribute by
是用来为sort by指定分区字段的(说白了就是map的key
)相同的key的会被分到一组。
现在再来测试:
select * from class distribute by name sort by name desc;
xjews 7514
xjews 7514
tom 7512
tim 7512
kom 7514
kim 7512
jsd 7514
jsd 7514
jedw 7511
tdsdwe 7512
tds 7512
rim 7512
lim 7514
lie23e 7514
jde 7511
ew 7514
xjs 7514
sju 7512
sjdweu 7512
riwedw 7512
jsew3d 7514
jsew3d 7514
jom 7511
jim 7511
je32 7511
可以看到 两个 xjews
被分到一组了,或许你觉得不具有代表性,你自己可以测试一下,这里的测试数据不太好。
那么为什么有了distribute by
就会根据其后面而定字段划分呢?你完全可以类比于mapreduce的分区,分区的原理是很具map的key来确定的。这里就是name(distribute by
后面的)。
如果分区是字符串: 字段值.hashCode % 分区数
如果分区字段是整型:字段值%分区数
这里的分区数与reducetask是一致的,也就是我前面通过设置set mapreduce.job.reduces=3
来改变的。在进行分区的时候,它会把上面计算结果相同的放到一个分区,那么久保证了相同数据在同一个分区。
对于cluster by 的话,由于不能指定排序,只能是升序,所以下面只演示升序结果:
select * from class cluster by name;
jedw 7511
jsd 7514
jsd 7514
kim 7512
kom 7514
tim 7512
tom 7512
xjews 7514
xjews 7514
ew 7514
jde 7511
lie23e 7514
lim 7514
rim 7512
tds 7512
tdsdwe 7512
je32 7511
jim 7511
jom 7511
jsew3d 7514
jsew3d 7514
riwedw 7512
sjdweu 7512
sju 7512
xjs 7514