优点: a. 学习成本低,只要会sql就能用hive b. 开发效率高,不需要编程,只需要写sql c. 模型简单,易于理解 d. 针对海量数据的高性能查询和分析 e. HiveQL 灵活的可扩展性(Extendibility) f. 高扩展性(Scalability)和容错性 g. 与 Hadoop 其他产品完全兼容
缺点: a. 不支持行级别的增删改 b. 不支持完整的在线事务处理 c. 本质上仍然是MR的执行,效率不算高
流程 1. 通过客户端提交一条Hql语句 2. 通过complier(编译组件)对Hql进行词法分析、语法分析。在这一步,编译器要知道此hql语句到底要操作哪张表 3. 去元数据库找表信息 4. 得到信息 5. complier编译器提交Hql语句分析方案 6. 执行流程 a. executor 执行器收到方案后,执行方案(DDL过程)。在这里注意,执行器在执行方案时,会进行判断:如果当前方案不涉及到MR组件,比如为表添加分区信息、比如字符串操作等,比如简单的查询操作等,此时就会直接和元数据库交互,然后去HDFS上去找具体数据;如果方案需要转换成MR job,则会将job 提交给Hadoop的JobTracker b. MR job完成,并且将运行结果写入到HDFS上 c. 执行器和HDFS交互,获取结果文件信息 7. 如果客户端提交Hql语句是带有查询结果性的,则会发生:7-8-9步,完成结果的查询。
优化
map side join a. mapJoin的主要意思就是,当连接的两个表是一个比较小的表和一个特别大的表的时候,可以把比较小的table直接放到内存中去,然后再对比较大的表格进行map操作,此时join就发生在map操作的时候,每当扫描一个大的table中的数据,就要去去查看小表的数据,哪条与之相符,继而进行连接。这里的join并不会涉及reduce操作。map端join的优势就是在于没有shuffle,在实际的应用中,设置方式:set hive.auto.convert.join=true; b. hive有一个参数:hive.mapjoin.smalltable.filesize,默认值是25mb(其中一个表大小小于25mb时,自动启用mapjoin) c. 要求:在hive做join时,要求小表在前(左)
join语句优化 优化前:select m.cid,u.id from order m join customer u on m.cid=u.id where m.dt=’20160801’; 优化后:select m.cid,u.id from (select cid from order where dt=’20160801’)m join customer u on m.cid = u.id
count distinct 优化 优化前:select count(distinct id )from tablename 优化后:select count(*) from (select distinct id from tablename)tmp; 分析: a. 优化前 i. 由于对id=引入了distinct操作,所以在Map阶段无法利用combine对输出结果去消重,必须将id作为key输出 ii. 在reduce阶段再对来自于不同的MapTask的结果进行消重,计入最终统计值 iii. 由于ReduceTask的数量默认为1,所以导致MapTask的所有结果都只能由这一个ReduceTask处理,这就使得ReduceTask的执行效率成为整个任务的瓶颈 iv. 虽然在使用hive的时候可以通过set mapred.reduce.tasks设置ReduceTask的数量,但是Hive在处理COUNT这种“全聚合(full aggregates)”计算时,它会忽略用户指定的Reduce Task数,而强制使用1
b. 优化后: i. 利用Hive对嵌套语句的支持,将原来一个MapReduce作业转换为两个作业:在第一阶段选出全部的非重复id,在第二阶段再对这些已消重的id进行计数 ii. 在第一阶段我们可以通过增大Reduce的并发数,并发处理Map输出 iii. 在第二阶段,由于id已经消重,因此COUNT(*)操作在Map阶段不需要输出原id数据,只输出一个合并后的计数即可。这样即使第二阶段Hive强制指定一个Reduce Task,极少量的Map输出数据也不会使单一的Reduce Task成为瓶颈 iv. 这一优化使得在同样的运行环境下,优化后的语句执行只需要原语句20%左右的时间
e. 调整切片数(map任务数) i. Hive底层自动对小文件做了优化,用了CombineTextInputFormat,将做个小文件切片合成一个切片。如果合成完之后的切片大小>mapred.max.split.size 的大小,就会生成一个新的切片 ii. mapred.max.split.size 默认是128MB,设置方式为:set mapred.max.split.size=134217728(128MB) iii. 对于切片数(MapTask)数量的调整,要根据实际业务来定,比如一个100MB的文件包含了有1千万条数据,此时可以调成10个MapTask,则每个MapTask处理1百万条数据。 f. JVM重利用 i. 设置方式:set mapred.job.reuse.jvm.num.tasks=20(默认是1个) ii. JVM重用是hadoop调优参数的内容,对hive的性能具有非常大的影响,特别是对于很难避免小文件的场景或者task特别多的场景,这类场景大多数执行时间都很短。这时JVM的启动过程可能会造成相当大的开销,尤其是执行的job包含有成千上万个task任务的情况 iii. JVM重用可以使得一个JVM进程在同一个JOB中重新使用N次后才会销毁。 g. 启用严格模式 i. 用户可以通过 set hive.mapred.mode=strict 来设置严格模式,改成unstrict则为非严格模式 ii. 在严格模式下,用户在运行如下query的时候会报错: i. 分区表的查询没有使用分区字段来限制 ii. 使用了order by 但没有使用limit语句(如果不使用limit,会对查询结果进行全局排序,消耗时间长) iii. 产生了笛卡尔积 h. 关闭推测执行机制 通常在测试环境下机会确定应用程序是否跑通,如果还加上推测执行,那么在数据分片本来就会发生数据倾斜,执行执行时间就是比其他的时间长,那么hive就会把这个执行时间长的job当作运行失败,继而又产生一个相同的job去运行,造成资源的浪费。可通过如下设置关闭推测执行: set mapreduce.map.speculative=false set mapreduce.reduce.speculative=false set hive.mapred.reduce.tasks.speculative.execution=false