对于 JOIN 操作:
INSERT OVERWRITE TABLE pv_users SELECT pv.pageid, u.age FROM page_view pv JOIN user u ON (pv.userid = u.userid);
实现过程为:
Map:
以 JOIN ON 条件中的列作为 Key,如果有多个列,则 Key 是这些列的组合
以 JOIN 之后所关心的列作为 Value,当有多个列时,Value 是这些列的组合。在 Value 中还会包含表的 Tag 信息,用于标明此 Value 对应于哪个表。
按照 Key 进行排序。
Shuffle:
根据 Key 的值进行 Hash,并将 Key/Value 对按照 Hash 值推至不同对 Reduce 中。
Reduce:
Reducer 根据 Key 值进行 Join 操作,并且通过 Tag 来识别不同的表中的数据。
具体实现过程如图:
SELECT pageid, age, count(1) FROM pv_users GROUP BY pageid, age;
SELECT age, count(distinct pageid) FROM pv_users GROUP BY age;
实现过程如图:
Hadoop和Hive都是用UTF-8编码的,所以, 所有中文必须是UTF-8编码, 才能正常使用。
备注:中文数据load到表里面, 如果字符集不同,很有可能全是乱码需要做转码的, 但是hive本身没有函数来做这个
hive.exec.compress.output 这个参数, 默认是 false,但是很多时候貌似要单独显式设置一遍,否则会对结果做压缩的,如果你的这个文件后面还要在hadoop下直接操作, 那么就不能压缩了
当前的 Hive 不支持在一条查询语句中有多 Distinct。如果要在 Hive 查询语句中实现多Distinct,需要使用至少 n+1 条查询语句(n为distinct的数目),前 n 条查询分 别对 n 个列去重,最后一条查询语句对 n 个去重之后的列做 Join 操作,得到最终结果。
只支持等值连接
只支持INSERT/LOAD操作,无UPDATE和DELTE
不支持HAVING操作。如果需要这个功能要嵌套一个子查询用where限制
Hive不支持where子句中的子查询
SQL标准中,任何对null的操作(数值比较,字符串操作等)结果都为null。Hive对null值处理的逻辑和标准基本一致,除了Join时的特殊逻辑。
这里的特殊逻辑指的是,Hive的Join中,作为Join key的字段比较,null=null是有意义的,且返回值为true。检查以下查询
select u.uid, count(u.uid) from t_weblog l join t_user u on (l.uid = u.uid) group by u.uid;
查询中,t_weblog表中uid为空的记录将和t_user表中uid为空的记录做连接,即l.uid = u.uid=null成立。
如果需要与标准一致的语义,我们需要改写查询手动过滤null值的情况:
select u.uid, count(u.uid) from t_weblog l join t_user u on (l.uid = u.uid and l.uid is not null and u.uid is not null) group by u.uid;
实践中,这一语义区别也是经常导致数据倾斜的原因之一。
分号是SQL语句结束标记,在HiveQL中也是,但是在HiveQL中,对分号的识别没有那么智慧,例如:
select concat(cookie_id,concat(';',’zoo’)) from c02_clickstat_fatdt1 limit 2; FAILED: Parse Error: line 0:-1 cannot recognize input '<EOF>' in function specification 可以推断,Hive解析语句的时候,只要遇到分号就认为语句结束,而无论是否用引号包含起来。
解决的办法是,使用分号的八进制的ASCII码进行转义,那么上述语句应写成:
select concat(cookie_id,concat('\073','zoo')) from c02_clickstat_fatdt1 limit 2;
为什么是八进制ASCII码?
我尝试用十六进制的ASCII码,但Hive会将其视为字符串处理并未转义,好像仅支持八进制,原因不详。这个规则也适用于其他非SELECT语句,如CREATE TABLE中需要定义分隔符,那么对不可见字符做分隔符就需要用八进制的ASCII码来转义。
根据语法Insert必须加“OVERWRITE”关键字,也就是说每一次插入都是一次重写。那如何实现表中新增数据呢?
假设Hive中有表xiaojun1,
hive> DESCRIBE xiaojun1; OK id int value int hive> SELECT * FROM xiaojun1; OK 3 4 1 2 2 3
现增加一条记录:
hive> INSERT OVERWRITE TABLE xiaojun1 SELECT id, value FROM ( SELECT id, value FROM xiaojun1 UNION ALL SELECT 4 AS id, 5 AS value FROM xiaojun1 limit 1 ) u; 结果是: hive>SELECT * FROM p1; OK 3 4 4 5 2 3 1 2
其中的关键在于, 关键字UNION ALL的应用, 即将原有数据集和新增数据集进行结合, 然后重写表
INSERT OVERWRITE TABLE在插入数据时,是按照后面的SELECT语句中的字段顺序插入的. 也就说, 当id 和value 的位置互换, 那么value将被写入id, 同id被写入value.
INSERT OVERWRITE TABLE在插入数据时, 后面的字段的初始值应注意与表定义中的一致性. 例如, 当为一个STRING类型字段初始为NULL时:
NULL AS field_name // 这可能会被提示定义类型为STRING, 但这里是void CAST(NULL AS STRING) AS field_name // 这样是正确的
又如, 为一个BIGINT类型的字段初始为0时:
CAST(0 AS BIGINT) AS field_name
jiewei