主要关注于执行性能问题
UDF:用户定义函数,可以直接在SQL语句中计算的函数,如:count、sum、avg、max、min等
SQL-1: SELECT date FROM test_table WHERE date = '20170829' and value = 1;
SQL-2: SELECT date FROM test_table PARTITION(p_20170829) p WHERE value = 1
SQL-1虽然通过where表达式能够筛选到并执行所需的分区,但是在分析的时候会先获取所有的分区列表再进行筛选,会导致更多的内存占用,显然SQL-2更优
简单了解什么是sql里的笛卡尔积
SQL-1: select * from gbk, utf8 where gbk.key= utf8.key
SQL-2: select * from gbk join utf8 where gbk.key= utf8.key
上面是先对tabel进行笛卡尔积再where筛选,应当按如下方式书写
select * from gbk join utf8 on gbk.key= utf8.key
读取一个表有多少行记录,虽然count也可以,但是速度非常慢!
show rowcount extended test;
按分区来显示每个分区有多少行记录
读取一个表有多大,单位是字节
show tablesize extended test;
MAPJION会把小表全部读入内存中,在map阶段直接拿另外一个表的数据和内存中表数据做匹配,由于在map是进行了join操作,省去了reduce运行的效率也会高很多。
简单说就是在Map阶段将小表读入内存,顺序扫描大表完成Join。这样就不会由于数据倾斜导致某个reduce上落数据太多而失败。
Join的时候,相同的key会hash到同一task中进行。如果某个key值太多,这个task就会成为瓶颈。
一种是唯一值非常少,极少数值有非常多的记录值(唯一值少于几千)
一种是唯一值比较多,这个字段的某些值有远远多于其他值的记录数,但是它的占比也小于百分之一或千分之一
简单来说就是大量的相同key被partition分配到一个分区里,造成了’一个人累死,其他人闲死’的情况,这种情况是我们不能接受的,这也违背了并行计算的初衷,首先一个节点要承受着巨大的压力,而其他节点计算完毕后要一直等待这个忙碌的节点,也拖累了整体的计算时间,可以说效率是十分低下的.
判断数据倾斜的方法:
任务中单个或者少量的task拖慢整个任务速度。
通过查看id的分布,返回表A的id分布情况,通过返回结果可以看出是否某些id的数量远大于其他。
select id,count(id) as id_nums group by id order by num desc
处理数据倾斜的方法
1、过滤或者去重:如果导致倾斜的id 在最后的结果没有作用,可以在Join 之前将其过滤掉。例如,id=NULL 的数据往往是多余的。
2、Map Join:如果join的表不大,使用Map Join。
3、数据分离:可以将表A 的数据分为两部分A1和A2,A1中不包含数据倾斜的数据(id=b),A2中只包含数据倾斜的数据(id=a)。A1和A2 分别与B 进行Join,然后将结果Union。SQL 如下所示。A1与A2 的Join 没有数据倾斜的问题。由于A2通常不会很大,A2与B的Join 采用Map Join。但是如果A2很大则不适用
4、数据打散:将有数据倾斜的表(A)中的id加上后缀,起到“打散”的作用,即"id_0"-“id_2”。为了结果正确性,小表B中的id需要将每条数据都“复制”多份。如下图所示。
数据分离:
select * from (
select * from A1 join B on A1.id = B.id
union all
select /*+ MAPJOIN (A2) */ * from A2 join B on A2.id = B.id
)
数据打散:
处理之前需要先查看一下id的分布情况
表A:
SELECT id, value, concat(id, string1(cast(rand() * 10000 as int)%3)) as new_id
FROM A;
表B:
SELECT id, value, concat(id, suffix) as new_id
FROM (
SELECT id, value, suffix
FROM B Lateral View explode(array(0,1,2)) tmp as suffix
)
如果Join 后有聚合函数操作,尽可能把聚合操作放到Join 之前,这样在Join 时 key 是单一的,避免数据倾斜。例如,
select t1.key, t1.total from
(select key ,sum(value) as total from t1 group by key
) t1
join t2 on t1.key = t2.key
前提是t2的key没有重复