Spark SQL之SQL优化

Spark SQL之SQL优化

主要关注于执行性能问题

1、避免使用不必要的UDF函数

UDF:用户定义函数,可以直接在SQL语句中计算的函数,如:count、sum、avg、max、min等

2、没有指定数据分区

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更优

3、避免使用笛卡尔积

简单了解什么是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

4、show Rowcount

读取一个表有多少行记录,虽然count也可以,但是速度非常慢!

show rowcount extended test;

按分区来显示每个分区有多少行记录

5、show Tablesize

读取一个表有多大,单位是字节

show tablesize extended test;

6、避免使用delete和update

7、当存在小表join的时候,查看是否可以使用mapjoin

MAPJION会把小表全部读入内存中,在map阶段直接拿另外一个表的数据和内存中表数据做匹配,由于在map是进行了join操作,省去了reduce运行的效率也会高很多。
简单说就是在Map阶段将小表读入内存,顺序扫描大表完成Join。这样就不会由于数据倾斜导致某个reduce上落数据太多而失败。

8、数据倾斜

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
)

9、join与groupby的顺序

如果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没有重复

你可能感兴趣的:(大数据,sql,spark,数据库)