Hive严格模式
前话:
order by 等。。
hive 中的 order by 语句会对查询结果做一次全局排序,即,所有的 mapper 产生的结果都会交给一个 reducer 去处理,无论数据量大小,job 任务只会启动一个 reducer,如果数据量巨大,则会耗费大量的时间。
注意:如果在严格模式下,order by 需要指定 limit 数据条数,不然数据量巨大的情况下会造成崩溃无输出结果。涉及属性:set hive.mapred.mode=nonstrict/strict
hive严格模式
hive提供了一个严格模式,可以防止用户执行那些可能产生意想不到的不好的效果的查询。即某些查询在严格
模式下无法执行。
配置中有个参数hive.mapred.mode,分为nonstrict,strict,默认是nonstrict
如果设置为strict,会对三种情况的语句在compile环节做过滤(可以禁止3中类型的查询):
1. 限制笛卡尔积的查询(笛卡尔积Join)。这种情况由于没有指定reduce join key,所以只会启用一个reducer,数据量大时会造成性能瓶颈
对关系型数据库非常了解的用户可能期望在执行join查询的时候不使用on语句而是使用where语句,这样关系数据库的执行
优化器就可以高效的将where语句转换成那个on语句。不幸的是,hive不会执行这种优化,因此,如果表足够大,那么这个查询就会
出现不可控的情况: 【用where而不是join就行了】
1 // Use only 1 reducer in case of cartesian product 2 if (reduceKeys.size() == 0) { 3 numReds = 1; 4 5 // Cartesian product is not supported in strict mode 6 if(conf.getVar(HiveConf.ConfVars.HIVEMAPREDMODE).equalsIgnoreCase("strict")) { 7 throw new SemanticException(ErrorMsg.NO_CARTESIAN_PRODUCT.getMsg()); 8 } 9 }
2. order by后面不跟limit。order by会强制将reduce number设置成1,不加limit,会将所有数据sink到reduce端来做全排序。
对于使用了orderby的查询,要求必须有limit语句。因为orderby为了执行排序过程会讲所有的结果分发到同一个reducer中
进行处理,强烈要求用户增加这个limit语句可以防止reducer额外执行很长一段时间: 【只需要增加limit语句就可以解决这个问题】
1 if (sortExprs == null) { 2 sortExprs = qb.getParseInfo().getOrderByForClause(dest); 3 if (sortExprs != null) { 4 assert numReducers == 1; 5 // in strict mode, in the presence of order by, limit must be specified 6 Integer limit = qb.getParseInfo().getDestLimit(dest); 7 if (conf.getVar(HiveConf.ConfVars.HIVEMAPREDMODE).equalsIgnoreCase("strict") 8 && limit == null) { 9 throw new SemanticException(generateErrorMessage(sortExprs, 10 ErrorMsg.NO_LIMIT_WITH_ORDERBY.getMsg())); 11 } 12 } 13 }
3. 带有分区的表的查询 :读取的表是partitioned table,但没有指定partition predicate。
注:如果是多级分区表的话,只要出现任何一个就放行
如果在一个分区表执行hive,除非where语句中包含分区字段过滤条件来显示数据范围,否则不允许执行。换句话说,
就是用户不允许扫描所有的分区。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速。
如果没有进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表: 【只需要在where语句中增加了一个分区过滤条件】
1 // If the "strict" mode is on, we have to provide partition pruner for 2 // each table. 3 if ("strict".equalsIgnoreCase(HiveConf.getVar(conf, 4 HiveConf.ConfVars.HIVEMAPREDMODE))) { 5 if (!hasColumnExpr(prunerExpr)) { 6 throw new SemanticException(ErrorMsg.NO_PARTITION_PREDICATE 7 .getMsg("for Alias \"" + alias + "\" Table \"" 8 + tab.getTableName() + "\"")); 9 } 10 }
这三种case在数据量比较大的情况下都会造成生成低效的MR Job,影响执行时间和效率,不过直接抛出exception又感觉太forcefully了。
可以在一些非线上生产环境下的ad-hoc查询端中开启strict mode,比如hiveweb,运营工具。
Losing her is blue like I've never know; 我从不知道失去她会这么伤心