zoukankan      html  css  js  c++  java
  • hive操作规范

    1.简述
    Hive 是基于Hadoop 构建的一套数据仓库分析系统,它提供了丰富的SQL查询方式来分析存储在Hadoop 分布式文件系统中的数据,可以将结构化的数据文件映射为一张数据库表,并提供完整的SQL查询功能,可以将SQL语句转换为MapReduce任务进行运行,通过自己的SQL 去查询分析需要的内容,这套SQL 简称Hive SQL,使不熟悉mapreduce 的用户很方便的利用SQL 语言查询,汇总,分析数据。而mapreduce开发人员可以把自己写的mapper 和reducer 作为插件来支持Hive 做更复杂的数据分析。
    它与关系型数据库的SQL 略有不同,但支持了绝大多数的语句如DDL、DML以及常见的聚合函数、连接查询、条件查询。HIVE不适合用于联机online)事务处理,也不提供实时查询功能。它最适合应用在基于大量不可变数据的批处理作业。
    HIVE的特点:可伸缩(在Hadoop的集群上动态的添加设备),可扩展,容错,输入格式的松散耦合。
    Hive 的官方文档中对查询语言有了很详细的描述,请参考:http://wiki.apache.org/hadoop/Hive/LanguageManual 。
    2. HIVE SQL语法规则
    2.1    数据类型
    2.1.1     整型
    TINYINT – 1字节整数
    SMALLINT – 2字节整数
    INT – 4字节整数
    BIGINT - 8 字节整数
    2.1.2     浮点型
    FLOAT – 单精度
    DOUBLE – 双精度
    2.1.3     DECIMAL类型
    DECIMAL(precision, scale)
    2.1.4     使用举例
    CREATE TABLE foo (colTinyInt TINYINT);
    CREATE TABLE foo (colInt INT);
    CREATE TABLE foo (colSmallInt SMALLINT);
    CREATE TABLE foo (colBigInt BIGINT);
    CREATE TABLE foo (colFloat FLOAT);
    CREATE TABLE foo (colDouble DOUBLE);
    CREATE TABLE foo (a DECIMAL,b DECIMAL(9, 7));
    2.1.5     日期类型
    TIMESTAMP – 时间戳类型
    说明:
    支持传统的unix时间戳,可选的纳秒级精度。
    支持的转换:
    整型数值类型:解读为以秒为单位的UNIX时间戳
    浮动点数值类型:解读为以秒和小数精度为单位的UNIX时间戳。
    字符串:JDBC兼容的java.sql.Timestamp格式“YYYY-MM-DD HH:MM:SS.fffffffff”(9位小数位精度)
    时间戳被解释是与timezone无关,存储为从UNIX纪元的偏移量。提供便利的UDF和时区转换(to_utc_timestamp,from_utc_timestamp)。
    所有现有datetime的UDF(月,日,年,小时,等)可以工作于TIMESTAMP数据类型。
    DATE  -  日期类型
    2.1.6     使用举例
    create table timestamp_udf (t timestamp);
    create table date_udf (t date);
    2.1.7     字符类型
    STRING – 字符串序列
    VARCHAR – 可变字符串序列
    CHAR – 单字符字符
    2.1.8     使用举例
    CREATE TABLE t1(colString STRING);
    CREATE TABLE t1(colVarchar VARCHAR(10));
    CREATE TABLE t1(colVarchar CHAR);
    2.1.9     复合类型
    arrays  -  数组
    maps  - 字典
    structs  - 结构体
    union  - 联合体(数据组合)
    2.1.10    使用举例
    创建数据库表,以array作为数据类型
    create table  person(name string,work_locations array<string>)
    ROW FORMAT DELIMITED
    FIELDS TERMINATED BY '	'
    COLLECTION ITEMS TERMINATED BY ',';
    数据
    biansutao beijing,shanghai,tianjin,hangzhou
    linan changchu,chengdu,wuhan
    
    创建数据库表,以map作为数据类型
    create table score(name string, score map<string,int>)
    ROW FORMAT DELIMITED
    FIELDS TERMINATED BY '	'
    COLLECTION ITEMS TERMINATED BY ','
    MAP KEYS TERMINATED BY ':';
     
    要入库的数据
    biansutao '数学':80,'语文':89,'英语':95
    jobs '语文':60,'数学':80,'英语':99
    
    创建数据库表,以struct作为数据类型
    CREATE TABLE test(id int,course struct<course:string,score:int>)
    ROW FORMAT DELIMITED
    FIELDS TERMINATED BY '	'
    COLLECTION ITEMS TERMINATED BY ',';
     
    数据
    1 english,80
    2 math,89
    3 chinese,95
    
    数据组合 (不支持组合的复杂数据类型)
    create table test1(id int,a MAP<STRING,ARRAY<STRING>>)
    row format delimited fields terminated by '	' 
    collection items terminated by ','
    MAP KEYS TERMINATED BY ':';
     
    1 english:80,90,70
    2 math:89,78,86
    3 chinese:99,100,82
    
    2.1.1     其它类型
    BOOLEAN - TRUE/FALSE
    BINARY  - 二进制类型
    2.1.2     使用举例
    CREATE TABLE t1(colBoolean BOOLEAN);
    CREATE TABLE t1(colBoolean binary);
    2.1.3     空值
    NULL – 空
    2.1.4     使用举例
    SELECT * FROM gdr WHERE imsi IS NULL;
    2.2    运算符及函数
    2.2.1     汇函数(Aggregate Functions)
    见下表
    返回类型    函数    说明
    bigint    count(*) , count(expr), count(DISTINCT expr[, expr_., expr_.])    返回记录条数。
    double    sum(col), sum(DISTINCT col)    求和
    double    avg(col), avg(DISTINCT col)    求平均值
    double    min(col)    返回指定列中最小值
    double    max(col)    返回指定列中最大值
    double    var_pop(col)    返回指定列的方差
    double    var_samp(col)    返回指定列的样本方差
    double    stddev_pop(col)    返回指定列的偏差
    double    stddev_samp(col)    返回指定列的样本偏差
    double    covar_pop(col1, col2)    两列数值协方差
    double    covar_samp(col1, col2)    两列数值样本协方差
    double    corr(col1, col2)    返回两列数值的相关系数
    double    percentile(col, p)    返回数值区域的百分比数值点。0<=P<=1,否则返回NULL,不支持浮点型数值。
    array<double>    percentile(col, array(p~1,, [, p,,2,,]…))    返回数值区域的一组百分比值分别对应的数值点。0<=P<=1,否则返回NULL,不支持浮点型数值。
    double    percentile_approx(col, p[, B])    Returns an approximate p^th^ percentile of a numeric column (including floating point types) in the group. The B parameter controls approximation accuracy at the cost of memory. Higher values yield better approximations, and the default is 10,000. When the number of distinct values in col is smaller than B, this gives an exact percentile value.
    array<double>    percentile_approx(col, array(p~1,, [, p,,2_]…) [, B])    Same as above, but accepts and returns an array of percentile values instead of a single one.
    array<struct{‘x’,'y’}>    histogram_numeric(col, b)    Computes a histogram of a numeric column in the group using b non-uniformly spaced bins. The output is an array of size b of double-valued (x,y) coordinates that represent the bin centers and heights
    array    collect_set(col)    返回无重复记录
    
    2.2.2    字符串函数
    见下表
    返回类型    函数    说明
    int    length(string A)    返回字符串的长度
    string    reverse(string A)    返回倒序字符串
    string    concat(string A, string B…)    连接多个字符串,合并为一个字符串,可以接受任意数量的输入字符串
    string    concat_ws(string SEP, string A, string B…)    链接多个字符串,字符串之间以指定的分隔符分开。
    string    substr(string A, int start) substring(string A, int start)    从文本字符串中指定的起始位置后的字符。
    string    substr(string A, int start, int len) substring(string A, int start, int len)    从文本字符串中指定的位置指定长度的字符。
    string    upper(string A) ucase(string A)    将文本字符串转换成字母全部大写形式
    string    lower(string A) lcase(string A)    将文本字符串转换成字母全部小写形式
    string    trim(string A)    删除字符串两端的空格,字符之间的空格保留
    string    ltrim(string A)    删除字符串左边的空格,其他的空格保留
    string    rtrim(string A)    删除字符串右边的空格,其他的空格保留
    string    regexp_replace(string A, string B, string C)    字符串A中的B字符被C字符替代
    string    regexp_extract(string subject, string pattern, int index)    通过下标返回正则表达式指定的部分。regexp_extract(‘foothebar’, ‘foo(.*?)(bar)’, 2) returns ‘bar.’
    string    parse_url(string urlString, string partToExtract [, string keyToExtract])    返回URL指定的部分。parse_url(‘http://facebook.com/path1/p.php?k1=v1&k2=v2#Ref1′, ‘HOST’) 返回:’facebook.com’
    string    get_json_object(string json_string, string path)    select a.timestamp, get_json_object(a.appevents, ‘$.eventid’), get_json_object(a.appenvets, ‘$.eventname’) from log a;
    string    space(int n)    返回指定数量的空格
    string    repeat(string str, int n)    重复N次字符串
    int    ascii(string str)    返回字符串中首字符的数字值
    string    lpad(string str, int len, string pad)    返回指定长度的字符串,给定字符串长度小于指定长度时,由指定字符从左侧填补。
    string    rpad(string str, int len, string pad)    返回指定长度的字符串,给定字符串长度小于指定长度时,由指定字符从右侧填补。
    array    split(string str, string pat)    将字符串转换为数组。
    int    find_in_set(string str, string strList)    返回字符串str第一次在strlist出现的位置。如果任一参数为NULL,返回NULL;如果第一个参数包含逗号,返回0。
    array<array<string>>    sentences(string str, string lang, string locale)    将字符串中内容按语句分组,每个单词间以逗号分隔,最后返回数组。 例如sentences(‘Hello there! How are you?’) 返回:( (“Hello”, “there”), (“How”, “are”, “you”) )
    array<struct<string,double>>    ngrams(array<array<string>>, int N, int K, int pf)    SELECT ngrams(sentences(lower(tweet)), 2, 100 [, 1000]) FROM twitter;
    array<struct<string,double>>    context_ngrams(array<array<string>>, array<string>, int K, int pf)    SELECT context_ngrams(sentences(lower(tweet)), array(null,null), 100, [, 1000]) FROM twitter;
    
    2.2.3    日期和时间函数
    见下表
    返回类型    函数    说明
    string    from_unixtime(bigint unixtime[, string format])    UNIX_TIMESTAMP参数表示返回一个值’YYYY- MM – DD HH:MM:SS’或YYYYMMDDHHMMSS.uuuuuu格式,这取决于是否是在一个字符串或数字语境中使用的功能。该值表示在当前的时区。
    bigint    unix_timestamp()    如果不带参数的调用,返回一个Unix时间戳(从’1970- 01 – 0100:00:00′到现在的UTC秒数)为无符号整数。
    bigint    unix_timestamp(string date)    指定日期参数调用UNIX_TIMESTAMP(),它返回参数值’1970- 01 – 0100:00:00′到指定日期的秒数。
    bigint    unix_timestamp(string date, string pattern)    指定时间输入格式,返回到1970年秒数:unix_timestamp(’2009-03-20′, ‘yyyy-MM-dd’) = 1237532400 参考:http://java.sun.com/j2se/1.4.2/docs/api/java/text/SimpleDateFormat.html
    
    string    to_date(string timestamp)    返回时间中的年月日: to_date(“1970-01-01 00:00:00″) = “1970-01-01″
    string    to_dates(string date)    给定一个日期date,返回一个天数(0年以来的天数)
    int    year(string date)    返回指定时间的年份,范围在1000到9999,或为”零”日期的0。
    int    month(string date)    返回指定时间的月份,范围为1至12月,或0一个月的一部分,如’0000-00-00′或’2008-00-00′的日期。
    int    day(string date) dayofmonth(date)    返回指定时间的日期
    int    hour(string date)    返回指定时间的小时,范围为0到23。
    int    minute(string date)    返回指定时间的分钟,范围为0到59。
    int    second(string date)    返回指定时间的秒,范围为0到59。
    int    weekofyear(string date)    返回指定日期所在一年中的星期号,范围为0到53。
    int    datediff(string enddate, string startdate)    两个时间参数的日期之差。
    int    date_add(string startdate, int days)    给定时间,在此基础上加上指定的时间段。
    int    date_sub(string startdate, int days)    给定时间,在此基础上减去指定的时间段。
    
    2.2.4    数学函数
    见下表
    返回类型    函数    说明
    BIGINT    round(double a)    四舍五入
    DOUBLE    round(double a, int d)    小数部分d位之后数字四舍五入,例如round(21.263,2),返回21.26
    BIGINT    floor(double a)    对给定数据进行向下舍入最接近的整数。例如floor(21.2),返回21。
    BIGINT    ceil(double a), ceiling(double a)    将参数向上舍入为最接近的整数。例如ceil(21.2),返回23.
    double    rand(), rand(int seed)    返回大于或等于0且小于1的平均分布随机数(依重新计算而变)
    double    exp(double a)    返回e的n次方
    double    ln(double a)    返回给定数值的自然对数
    double    log10(double a)    返回给定数值的以10为底自然对数
    double    log2(double a)    返回给定数值的以2为底自然对数
    double    log(double base, double a)    返回给定底数及指数返回自然对数
    double    pow(double a, double p) power(double a, double p)    返回某数的乘幂
    double    sqrt(double a)    返回数值的平方根
    string    bin(BIGINT a)    返回二进制格式,参考:http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_hex
    
    string    hex(BIGINT a) hex(string a)    将整数或字符转换为十六进制格式。参考:http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_hex
    
    string    unhex(string a)    十六进制字符转换由数字表示的字符。
    string    conv(BIGINT num, int from_base, int to_base)    将指定数值,由原来的度量体系转换为指定的试题体系。例如CONV(‘a’,16,2),返回。参考:’1010′ http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_conv
    double    abs(double a)    取绝对值
    int double    pmod(int a, int b) pmod(double a, double b)    返回a除b的余数的绝对值
    double    sin(double a)    返回给定角度的正弦值
    double    asin(double a)    返回x的反正弦,即是X。如果X是在-1到1的正弦值,返回NULL。
    double    cos(double a)    返回余弦
    double    acos(double a)    返回X的反余弦,即余弦是X,,如果-1<= A <= 1,否则返回null.
    int double    positive(int a) positive(double a)    返回A的值,例如positive(2),返回2。
    int double    negative(int a) negative(double a)    返回A的相反数,例如negative(2),返回-2。
    
    2.2.5    算术运算符
    见下表
    运算符    类型    说明
    A + B    所有数字类型    A和B相加。结果的与操作数值有共同类型。例如每一个整数是一个浮点数,浮点数包含整数。所以,一个浮点数和一个整数相加结果也是一个浮点数。
    A – B    所有数字类型    A和B相减。结果的与操作数值有共同类型。
    A * B    所有数字类型    A和B相乘,结果的与操作数值有共同类型。需要说明的是,如果乘法造成溢出,将选择更高的类型。
    A / B    所有数字类型    A和B相除,结果是一个double(双精度)类型的结果。
    A % B    所有数字类型    A除以B余数与操作数值有共同类型。
    A & B    所有数字类型    运算符查看两个参数的二进制表示法的值,并执行按位”与”操作。两个表达式的一位均为1时,则结果的该位为 1。否则,结果的该位为 0。
    A|B    所有数字类型     运算符查看两个参数的二进制表示法的值,并执行按位”或”操作。只要任一表达式的一位为 1,则结果的该位为 1。否则,结果的该位为 0。 
    A ^ B    所有数字类型    运算符查看两个参数的二进制表示法的值,并执行按位”异或”操作。当且仅当只有一个表达式的某位上为 1 时,结果的该位才为 1。否则结果的该位为 0。
    ~A    所有数字类型    对一个表达式执行按位”非”(取反)。
    
    2.2.6    逻辑运算符
    见下表
    运算符    类型    说明
    A AND B    布尔值    A和B同时正确时,返回TRUE,否则FALSE。如果A或B值为NULL,返回NULL。
    A && B    布尔值    与”A AND B”相同
    A OR B    布尔值    A或B正确,或两者同时正确返返回TRUE,否则FALSE。如果A和B值同时为NULL,返回NULL。
    A | B    布尔值    与”A OR B”相同
    NOT A    布尔值    如果A为NULL或错误的时候返回TURE,否则返回FALSE。
    ! A    布尔值    与”NOT A”相同
    
    2.2.7    比较运算符
    见下表
    运算符    类型    说明
    A = B    所有原始类型    如果A与B相等,返回TRUE,否则返回FALSE
    A == B    无    失败,因为无效的语法。 SQL使用”=”,不使用”==”。
    A <> B    所有原始类型    如果A不等于B返回TRUE,否则返回FALSE。如果A或B值为”NULL”,结果返回”NULL”。
    A < B    所有原始类型    如果A小于B返回TRUE,否则返回FALSE。如果A或B值为”NULL”,结果返回”NULL”。
    A <= B    所有原始类型    如果A小于等于B返回TRUE,否则返回FALSE。如果A或B值为”NULL”,结果返回”NULL”。
    A > B    所有原始类型    如果A大于B返回TRUE,否则返回FALSE。如果A或B值为”NULL”,结果返回”NULL”。
    A >= B    所有原始类型    如果A大于等于B返回TRUE,否则返回FALSE。如果A或B值为”NULL”,结果返回”NULL”。
    A IS NULL    所有类型    如果A值为”NULL”,返回TRUE,否则返回FALSE
    A IS NOT NULL    所有类型    如果A值不为”NULL”,返回TRUE,否则返回FALSE
    A LIKE B    字符串    如果A或B值为”NULL”,结果返回”NULL”。字符串A与B通过sql进行匹配,如果相符返回TRUE,不符返回FALSE。B字符串中 的”_”代表任一字符,”%”则代表多个任意字符。例如: (‘foobar’ like ‘foo’)返回FALSE,( ‘foobar’ like ‘foo_ _ _’或者 ‘foobar’ like ‘foo%’)则返回TURE
    A RLIKE B    字符串    如果A或B值为”NULL”,结果返回”NULL”。字符串A与B通过java进行匹配,如果相符返回TRUE,不符返回FALSE。例如:( ‘foobar’ rlike ‘foo’)返回FALSE,(’foobar’ rlike ‘^f.*r$’ )返回TRUE。
    A REGEXP B    字符串    与RLIKE相同。
    
    2.2.8    复合类型构建
    见下表
    方法名称    操作数    描述
    map    (key1, value1, key2, value2, ...)    根据输入的key/value对,创建map结构
    struct    (val1, val2, val3, ...)    根据参数列值,创建struct结构
    array    (val1, val2, ...)    根据输入参数列值,创建数组结构,array中的值必须是同一种类型
    2.2.9    使用举例
    SELECT map(msisdn,start_time) FROM test;
    SELECT struct(start_time,msisdn) FROM test
    SELECT array(start_time,msisdn) FROM test;
    SELECT size(map(start_time,msisdn)) FROM test;
    SELECT size(array(start_time,msisdn)) FROM test;
    2.2.10    收集函数
    见下表
    返回值    名称(用法)    描述
    int    size(Map<K.V>)    返回map结构的元素个数
    int    size(Array<T>)    返回Array类型的元素个数
    2.2.11    使用举例
    SELECT size(map(start_time,msisdn)) FROM test;
    SELECT size(array(start_time,msisdn)) FROM test;
    2.2.12    条件函数
    返回类型    函数    说明
    T    if(boolean testCondition, T valueTrue, T valueFalseOrNull)    判断是否满足条件,如果满足返回一个值,如果不满足则返回另一个值。
    T    COALESCE(T v1, T v2, …)    返回一组数据中,第一个不为NULL的值,如果均为NULL,返回NULL。
    T    CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END    当a=b时,返回c;当a=d时,返回e,否则返回f。
    T    CASE WHEN a THEN b [WHEN c THEN d]* [ELSE e] END    当值为a时返回b,当值为c时返回d。否则返回e。
    
    2.2.13    复杂类型函数操作
    函数    类型    说明
    A[n]    A是一个数组,n为int型    返回数组A的第n个元素,第一个元素的索引为0。如果A数组为['foo','bar'],则A[0]返回’foo’和A[1]返回”bar”。
    M[key]    M是Map<K, V>,关键K型    返回关键值对应的值,例如mapM为 {‘f’ -> ‘foo’, ‘b’ -> ‘bar’, ‘all’ -> ‘foobar’},则M['all'] 返回’foobar’。
    S.x    S为struct类型    返回结构x字符串在结构S中的存储位置。如 foobar {int foo, int bar} foobar.foo的领域中存储的整数。
    
    2.2.14    类型转换函数
    见下表
    返回类型    函数    说明
    指定 “type”    cast(expr as <type>)    类型转换。例如将字符”1″转换为整数:cast(’1′ as bigint),如果转换失败返回NULL。
    2.2.15    GBD自定义函数
    参考:http://itdocshare.pingan.com.cn/sites/kfsb/Hadoop/Forms/AllItems.aspx?RootFolder=%2fsites%2fkfsb%2fHadoop%2f%e5%b9%b3%e5%8f%b0%e6%96%87%e6%a1%a3%2fHIVE%20UDF%20%e8%af%b4%e6%98%8e%e6%96%87%e6%a1%a3&FolderCTID=&View=%7b4D5B74C3%2d9361%2d439B%2dB6BE%2d235A2D269477%7d
    
    2.3    数据定义命令(DDL)
    2.3.1     建表
    CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name 
      [(col_name data_type [COMMENT col_comment], ...)] 
      [COMMENT table_comment] 
      [PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)] 
      [CLUSTERED BY (col_name, col_name, ...) 
      [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS] 
      [ROW FORMAT row_format] 
      [STORED AS file_format] 
      [LOCATION hdfs_path]
    
    2.3.2     注意事项
    1)    CREATE TABLE 创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常;用户可以用 IF NOT EXIST 选项来忽略这个异常
    2)    EXTERNAL 关键字可以让用户创建一个外部表,在建表的同时指定一个指向实际数据的路径(LOCATION)
    3)    LIKE 允许用户复制现有的表结构,但是不复制数据
    4)    COMMENT可以为表与字段增加描述
    5)    ROW FORMAT
        DELIMITED [FIELDS TERMINATED BY char] [COLLECTION ITEMS TERMINATED BY char]
            [MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]
       | SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value, property_name=property_value, ...)]
             用户在建表的时候可以自定义 SerDe 或者使用自带的 SerDe。如果没有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED,将会使用自带的 SerDe。在建表的时候,用户还需要为表指定列,用户在指定表的列的同时也会指定自定义的 SerDe,Hive 通过 SerDe 确定表的具体的列的数据。
    6)    STORED AS
                SEQUENCEFILE
                | TEXTFILE
                | RCFILE    
                | INPUTFORMAT input_format_classname OUTPUTFORMAT             output_format_classname
           如果文件数据是纯文本,可以使用 STORED AS TEXTFILE。如果数据需要压缩,使用 STORED AS SEQUENCE 。
    2.3.3     使用示例
    1)    创建简单表:
    hive> CREATE TABLE pokes (foo INT, bar STRING); 
    
    2)    创建外部表:
    CREATE EXTERNAL TABLE page_view(viewTime INT, userid BIGINT,
         page_url STRING, referrer_url STRING,
         ip STRING COMMENT 'IP Address of the User',
         country STRING COMMENT 'country of origination')
     COMMENT 'This is the staging page view table'
     ROW FORMAT DELIMITED FIELDS TERMINATED BY '54'
     STORED AS TEXTFILE
     LOCATION '<hdfs_location>';
    3)    建分区表
    CREATE TABLE par_table(viewTime INT, userid BIGINT,
         page_url STRING, referrer_url STRING,
         ip STRING COMMENT 'IP Address of the User')
     COMMENT 'This is the page view table'
     PARTITIONED BY(date STRING, pos STRING)
    ROW FORMAT DELIMITED ‘	’
       FIELDS TERMINATED BY '
    '
    STORED AS SEQUENCEFILE;
    4)    建Bucket表
    CREATE TABLE par_table(viewTime INT, userid BIGINT,
         page_url STRING, referrer_url STRING,
         ip STRING COMMENT 'IP Address of the User')
     COMMENT 'This is the page view table'
     PARTITIONED BY(date STRING, pos STRING)
     CLUSTERED BY(userid) SORTED BY(viewTime) INTO 32 BUCKETS
     ROW FORMAT DELIMITED ‘	’
       FIELDS TERMINATED BY '
    '
    STORED AS SEQUENCEFILE;
    
    5)    创建表并创建索引字段ds
    hive> CREATE TABLE invites (foo INT, bar STRING) PARTITIONED BY (ds STRING); 
    复制一个空表
    CREATE TABLE empty_key_value_store
    LIKE key_value_store;
    
    2.3.4     修改表结构
    1)    增加分区、删除分区
    增加
    ALTER TABLE table_name ADD [IF NOT EXISTS] partition_spec [ LOCATION 'location1' ] partition_spec [ LOCATION 'location2' ] ...
          partition_spec:
      : PARTITION (partition_col = partition_col_value, partition_col = partiton_col_value, ...)
    删除
    ALTER TABLE table_name DROP partition_spec, partition_spec,...
    2)    重命名表
    ALTER TABLE table_name RENAME TO new_table_name
    3)    修改列的名字、类型、位置、注释
    ALTER TABLE table_name CHANGE [COLUMN] col_old_name col_new_name column_type [COMMENT col_comment] [FIRST|AFTER column_name]
    4)    增加/更新列
    ALTER TABLE table_name ADD|REPLACE COLUMNS (col_name data_type [COMMENT col_comment], ...)  
    5)    增加表的元数据信息
    ALTER TABLE table_name SET TBLPROPERTIES table_properties table_properties:
             :[property_name = property_value…..]
    2.3.5    删表
    DROP TABLE [IF EXISTS] table_name
    2.4    数据操作命令(DML)
    2.4.1     LOAD DATA
    2.4.1.1    语法规则
    LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
    2.4.1.2    使用说明
    1)    LOAD DATA命令主要用于装载已有文件到新的TABLE中,只是拷贝或搬移文件,并不做内容的校验。
    2)    语法规则中,LOCAL表示从本地文件系统LOAD文件,否则就是从HDFS中取文件,OVERWRITE表示覆盖已有的数据。
    2.4.1.3    使用示例
    hive> LOAD DATA LOCAL INPATH './examples/files/kv1.txt' OVERWRITE INTO TABLE pokes;
    2.4.2     INSERT
    2.4.2.1    基本模式
    INSERT OVERWRITE TABLE tablename PARTITION (partcol1[=val1], partcol2[=val2] ...) select_statement FROM from_statement
    2.4.2.2    多插入模式
    FROM from_statement
    INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1
    [INSERT OVERWRITE TABLE tablename2 [PARTITION ...] select_statement2] ...
    2.4.2.3    将查询结果写入HDFS文件系统
    INSERT OVERWRITE [LOCAL] DIRECTORY directory1 SELECT ... FROM ...
            FROM from_statement
            INSERT OVERWRITE [LOCAL] DIRECTORY directory1 select_statement1
         [INSERT OVERWRITE [LOCAL] DIRECTORY directory2 select_statement2]
    2.4.2.4    INSERT INTO
    INSERT INTO  TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...)] select_statement1 FROM from_statement
    2.4.2.5    使用示例
    将查询数据输出至目录:
    hive> INSERT OVERWRITE DIRECTORY '/tmp/hdfs_out' SELECT a.* FROM invites a WHERE a.ds='<DATE>';
    将查询结果输出至本地目录:
    hive> INSERT OVERWRITE LOCAL DIRECTORY '/tmp/local_out' SELECT a.* FROM pokes a;
    选择所有列到本地目录 :
    hive> INSERT OVERWRITE TABLE events SELECT a.* FROM profiles a;
    hive> INSERT OVERWRITE TABLE events SELECT a.* FROM profiles a WHERE a.key < 100;
    hive> INSERT OVERWRITE LOCAL DIRECTORY '/tmp/reg_3' SELECT a.* FROM events a;
    hive> INSERT OVERWRITE DIRECTORY '/tmp/reg_4' select a.invites, a.pokes FROM profiles a;
    hive> INSERT OVERWRITE DIRECTORY '/tmp/reg_5' SELECT COUNT(1) FROM invites a WHERE a.ds='<DATE>';
    hive> INSERT OVERWRITE DIRECTORY '/tmp/reg_5' SELECT a.foo, a.bar FROM invites a;
    hive> INSERT OVERWRITE LOCAL DIRECTORY '/tmp/sum' SELECT SUM(a.pc) FROM pc1 a;
    将一个表的统计结果插入另一个表中:
    hive> FROM invites a INSERT OVERWRITE TABLE events SELECT a.bar, count(1) WHERE a.foo > 0 GROUP BY a.bar;
    hive> INSERT OVERWRITE TABLE events SELECT a.bar, count(1) FROM invites a WHERE a.foo > 0 GROUP BY a.bar;
    JOIN
    hive> FROM pokes t1 JOIN invites t2 ON (t1.bar = t2.bar) INSERT OVERWRITE TABLE events SELECT t1.bar, t1.foo, t2.foo;
    将多表数据插入到同一表中:
    FROM src
    INSERT OVERWRITE TABLE dest1 SELECT src.* WHERE src.key < 100
    INSERT OVERWRITE TABLE dest2 SELECT src.key, src.value WHERE src.key >= 100 and src.key < 200
    INSERT OVERWRITE TABLE dest3 PARTITION(ds='2008-04-08', hr='12') SELECT src.key WHERE src.key >= 200 and src.key < 300
    INSERT OVERWRITE LOCAL DIRECTORY '/tmp/dest4.out' SELECT src.value WHERE src.key >= 300;
    将文件流直接插入文件:
    hive> FROM invites a INSERT OVERWRITE TABLE events SELECT TRANSFORM(a.foo, a.bar) AS (oof, rab) USING '/bin/cat' WHERE a.ds > '2008-08-09';
    2.5    数据查询SQL
    2.5.1     基本的SQL操作
    2.5.1.1    语法规则
    SELECT [ALL | DISTINCT] select_expr, select_expr, ...
    FROM table_reference
    [WHERE where_condition]
    [GROUP BY col_list [HAVING condition]]
    [   CLUSTER BY col_list
      | [DISTRIBUTE BY col_list] [SORT BY| ORDER BY col_list]
    ]
    [LIMIT number]
    2.5.1.2    使用说明
    1)    使用ALL和DISTINCT选项区分对重复记录的处理。默认是ALL,表示查询所有记录。DISTINCT表示去掉重复的记录
    2)    Where 条件类似我们传统SQL的where 条件,目前支持 AND,OR ,0.9版本支持between,IN, NOT IN,不支持EXIST ,NOT EXIST
    3)    ORDER BY与SORT BY的不同
    ORDER BY 全局排序,只有一个Reduce任务
    SORT BY 只在本机做排序
    4)    Limit
    Limit 可以限制查询的记录数
    例如:SELECT * FROM t1 LIMIT 5
    实现Top k 查询,下面的查询语句查询销售记录最大的 5 个销售代表。
    例如:
    SET mapred.reduce.tasks = 1 
        SELECT * FROM test SORT BY amount DESC LIMIT 5
    5)    REGEX Column Specification
    SELECT 语句可以使用正则表达式做列选择,下面的语句查询除了 ds 和 hr 之外的所有列:
    SELECT `(ds|hr)?+.+` FROM test
    2.5.1.3    使用示例
    SELECT a.foo FROM invites a WHERE a.ds='<DATE>';
    2.5.2     基于Partition的查询
    2.5.2.1    使用说明
    1)    一般 SELECT 查询会扫描整个表,使用 PARTITIONED BY 子句建表,查询就可以利用分区剪枝(input pruning)的特性
    2)    Hive 当前的实现是,只有分区断言出现在离 FROM 子句最近的那个WHERE 子句中,才会启用分区剪枝
    2.5.3     JOIN
    2.5.3.1    语法规则
    join_table: 
       table_reference JOIN table_factor [join_condition] 
      | table_reference {LEFT|RIGHT|FULL} [OUTER] JOIN table_reference join_condition 
      | table_reference LEFT SEMI JOIN table_reference join_condition 
    
    table_reference: 
        table_factor 
      | join_table 
    
    table_factor: 
        tbl_name [alias] 
      | table_subquery alias 
      | ( table_references ) 
    
    join_condition: 
        ON equality_expression ( AND equality_expression )* 
    
    equality_expression: 
        expression = expression
    2.5.3.2    使用说明
    1)    Hive 只支持等值连接(equality joins)、外连接(outer joins)和(left semi joins)。Hive 不支持所有非等值的连接,因为非等值连接非常难转化到 map/reduce 任务
    2)    LEFT,RIGHT和FULL OUTER关键字用于处理join中空记录的情况
    3)    LEFT SEMI JOIN 是 IN/EXISTS 子查询的一种更高效的实现
    4)    join 时,每次 map/reduce 任务的逻辑是这样的:reducer 会缓存 join 序列中除了最后一个表的所有表的记录,再通过最后一个表将结果序列化到文件系统
    5)    实践中,应该把最大的那个表写在最后
    6)    join 查询时,需要注意几个关键点
    6.1) 只支持等值join
    SELECT a.* FROM a JOIN b ON (a.id = b.id)
    SELECT a.* FROM a JOIN b ON (a.id = b.id AND a.department = b.department)
    6.2) 可以 join 多于 2 个表,例如
          SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)
    6.3) 如果join中多个表的 join key 是同一个,则 join 会被转化为单个 map/reduce 任务
    7)    LEFT,RIGHT和FULL OUTER
    例子
    SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key)
    7.1) 如果你想限制 join 的输出,应该在 WHERE 子句中写过滤条件——或是在 join 子句中写
    7.2) 容易混淆的问题是表分区的情况
    SELECT c.val, d.val FROM c LEFT OUTER JOIN d ON (c.key=d.key) WHERE a.ds='2010-07-07' AND b.ds='2010-07-07‘
    如果 d 表中找不到对应 c 表的记录,d 表的所有列都会列出 NULL,包括 ds 列。也就是说,join 会过滤 d 表中不能找到匹配 c 表 join key 的所有记录。这样的话,LEFT OUTER 就使得查询结果与 WHERE 子句无关
    解决办法
    SELECT c.val, d.val FROM c LEFT OUTER JOIN d ON (c.key=d.key AND d.ds='2009-07-07' AND c.ds='2009-07-07')
    8)    LEFT SEMI JOIN
    LEFT SEMI JOIN 的限制是, JOIN 子句中右边的表只能在 ON 子句中设置过滤条件,在 WHERE 子句、SELECT 子句或其他地方过滤都不行
    SELECT a.key, a.value 
      FROM a 
      WHERE a.key in 
       (SELECT b.key 
        FROM B);
           可以被重写为:
          SELECT a.key, a.val 
       FROM a LEFT SEMI JOIN b on (a.key = b.key)
    9)    UNION ALL
    用来合并多个select的查询结果,需要保证select中字段须一致
    select_statement UNION ALL select_statement UNION ALL select_statement ...
    2.6    HIVE SQL使用注意事项
    2.6.1     HIVE不支持非等值连接
    SQL中对两表内联可以写成:
    select * from dual a,dual b where a.key = b.key;
    Hive中应为
    select * from dual a join dual b on a.key = b.key; 
    而不是传统的格式:
    SELECT t1.a1 as c1, t2.b1 as c2FROM t1, t2 WHERE t1.a2 = t2.b2
    2.6.2     分号字符
    分号是SQL语句结束标记,在HiveQL中也是,但是在HiveQL中,对分号的识别没有那么智慧,例如:
    select concat(key,concat(';',key)) from dual;
    但HiveQL在解析语句时提示:
            FAILED: Parse Error: line 0:-1 mismatched input '<EOF>' expecting ) in function specification
    解决的办法是,使用分号的八进制的ASCII码进行转义,那么上述语句应写成:
    select concat(key,concat('73',key)) from dual;
    2.6.3     IS [NOT] NULL
    SQL中null代表空值, 值得警惕的是, 在HiveQL中String类型的字段若是空(empty)字符串, 即长度为0, 那么对它进行IS NULL的判断结果是False
    2.6.4     Hive不支持将数据插入现有的表或分区中,仅支持覆盖重写整个表
    例如:
    INSERT OVERWRITE TABLE t1  SELECT * FROM t2;  
    2.6.5     Hive支持嵌入mapreduce程序,来处理复杂逻辑
    例如:
    FROM (  
    MAP doctext USING 'python wc_mapper.py' AS (word, cnt)  
    FROM docs  
    CLUSTER BY word  
    ) a  
    REDUCE word, cnt USING 'python wc_reduce.py';  
    
    --doctext: 是输入
    --word, cnt: 是map程序的输出
    
    --CLUSTER BY: 将wordhash后,又作为reduce程序的输入
    
    
    
    并且map程序、reduce程序可以单独使用,如:
    
    
    FROM (  
    FROM session_table  
    SELECT sessionid, tstamp, data  
    DISTRIBUTE BY sessionid SORT BY tstamp  
    ) a  
    REDUCE sessionid, tstamp, data USING 'session_reducer.sh';  
    --DISTRIBUTE BY: 用于给reduce程序分配行数据
    2.6.6     Hive支持动态设置环境变量
    例如,当启动一个执行环境后,可以调用如下命令:
    set mapred.job.queue.nam=queue01;
    2.6.7     Hive环境默认是default数据库,需用use切换数据库
    例如,当启动一个执行环境后,可以调用如下命令:
    use test_databases;
    3.    优化实例及常见异常
    3.1    执行日志
    hive执行过程中会输出很多日志,一般执行错误情况下,终端直接会输出错误信息,比如没有此表,或者没有权限等,很多显而易见的错误,大家可以自行解决,实在解决不了的再发邮件一起解决。
    3.2    提前过滤数据,减少中间数据依赖
    尽量尽早地过滤数据,减少每个阶段的数据量,对于分区表要加分区,同时只选择需要使用到的字段。
    select ... from A
    join B
    on A.key = B.key
    where A.userid>10
         and B.userid<10
            and A.dt='20120417'
            and B.dt='20120417';
    应该改写为:
    select .... from (select .... from A
                      where dt='201200417'
                                        and userid>10
                                  ) a
    join ( select .... from B
           where dt='201200417'
                         and userid < 10   
         ) b
    on a.key = b.key;
    3.3    慎用map join
    慎重使用mapjoin,一般行数小于2000行,大小小于1M(扩容后可以适当放大)的表才能使用,小表要注意放在join的左边。否则会引起磁盘和内存的大量消耗
    3.4    禁止使用笛卡尔积
    笛卡尔积只有1个reduce任务,会导致计算超慢,甚至可能计算不出来或者导致节点挂掉。
    1)    以下两种形式的SQL会导致笛卡尔积:
    select * from gbk, utf8 where gbk.key= utf8.key and gbk.key > 10;
    select * from gbk join utf8 where gbk.key= utf8.key and gbk.key > 10;
    连接的规范形式:
    select * from gbk join utf8 on gbk.key= utf8.key where gbk.key > 10;
    2)    此外,当多个数据表做连接时,有些童靴喜欢写成以下形式:
     tablea join tableb join tablec join ... on tablea.col1 = tableb.col2 and ...
    这种形式也会导致笛卡尔积。正确的写法是:
     tablea join tableb on ( tablea.col1 = tableb.col2 and ... ) join tablec on  ...  join  ... on  ...
    至于连接条件中有or这种情况,可以考虑使用join + union all或者in等方式来改写。
    3)    只有一种情况下可以考虑使用笛卡尔积:
    连接条件时不等式。
    4)    请注意,如果必须使用笛卡尔积,刚好其中有一个表符合map join的要求,那么一定要使用map join来加速。map join的使用方法后面有详细描述。
    3.5    列修剪和分区修剪
    1)    列裁剪(Column Pruning)
    在读数据的时候,只读取查询中需要用到的列,而忽略其他列。例如,对于查询:
    SELECT a,b FROM T WHERE e < 10;
    其中,T 包含 5 个列 (a,b,c,d,e),列 c,d 将会被忽略,只会读取a, b, e 列
    这个选项参数默认为真: hive.optimize.cp = true
    2)    分区裁剪(Partition Pruning)
    在查询的过程中减少不必要的分区。例如,对于下列查询:
    SELECT * FROM (SELECT c1, COUNT(1)
      FROM T GROUP BY c1) subq
      WHERE subq.prtn = 100;
    
    SELECT * FROM T1 JOIN
      (SELECT * FROM T2) subq ON (T1.c1=subq.c2)
      WHERE subq.prtn = 100;
    会在子查询中就考虑 subq.prtn = 100 条件,从而减少读入的分区数目。
    此选项参数默认为真:hive.optimize.pruner=true
    3.6    explain的使用
    explain命令对于我们优化查询语句很重要,针对某些查询语句,我们可以通过它查看各个执行计划,针对耗时的地方,优化之。
    1)    语法如下:EXPLAIN [EXTENDED] query
    2)    参考使用方法:http://www.cnblogs.com/ggjucheng/archive/2013/01/16/2861665.html 
    3.7    uion all改写成join
    当需要把几个数据集的结果合并时,能使用join的话就不要使用union all。因为使用union all时通常需要加入大量的0,这会导致中间结果膨胀,增加系统负担。
    3.8    大数据量时,怎样让全局count/sum distinct更快?
    以下两个SQL,有人可能认为例句1快于例句2。
    例句1:
    SELECT
            COUNT(DISTINCT uin) login_uins   
        FROM
            tabled
        WHERE
            ftime >= 20121001
            AND ftime <= 20121001
    例句2:      
    SELECT
            COUNT(uin) login_uins
        FROM
            ( select distinct uin from tabled  WHERE
            ftime >= 20121001
            AND ftime <= 20121001   ) subq
    实际上,例句2远远快于例句1。元芳,你怎么看?
    例句1虽然只有1个mr,但是,这个mr却只有1个reduce任务,导致这个reduce任务需要读取和处理大量的数据,这不仅导致执行慢,而且,在如果tabled中的数据量太大,可能导致执行reduce任务的节点down掉。
           例句2先去重,后全局统计,没有像例句1那样明显的瓶颈。所以,请牢记当对某个数据集进行全局count distinct操作时,尽量用例句2的形式。
    在其他情况下,即使有group by,但是group by的维度太低,也可以考虑这种改写方法。也就是说,一定要避免group by的维度太低。
    3.9    有小表存在的情况下,看看能否使用map join
    使用Map Join的必要条件:
    a.参与连接的小表的行数,以不超过2万条为宜。
    b.连接类型是inner join、right outer join(小表不能是右表)、left outer join(小表不能是左表)、left semi join。
    使用方法示例:
    例如:
    INSERT OVERWRITE TABLE pv_users
    SELECT /*+ MAPJOIN(pv) */   
    pv.pageid, u.age                                 
    FROM page_view pv
    JOIN user u
    ON (pv.userid = u.userid);
    注:当大表存在数据倾斜时,如果小表符合map join的要求,使用map join会极大加速计算。
    3.10    数据倾斜(转载)
    数据倾斜的外在表现是执行时间超长。查看任务的监控页面可以发现,除了一个或几个任务外,其他reduce任务都执行的很快。这种情况下,只有一个解释:数据倾斜。
    在做Shuffle阶段的优化过程中,遇到了数据倾斜的问题,造成了对一些情况下优化效果不明显。主要是因为在Job完成后的所得到的Counters是整个Job的总和,优化是基于这些Counters得出的平均值,而由于数据倾斜的原因造成map处理数据量的差异过大,使得这些平均值能代表的价值降低。Hive的执行是分阶段的,map处理数据量的差异取决于上一个stage的reduce输出,所以如何将数据均匀的分配到各个reduce中,就是解决数据倾斜的根本所在。规避错误来更好的运行比解决错误更高效。在查看了一些资料后,总结如下。
    1)    数据倾斜的原因
    1.1)    操作:
    关键词    情形    后果
    Join    其中一个表较小,
    但是key集中    分发到某一个或几个Reduce上的数据远高于平均值
        大表与大表,但是分桶的判断字段0值或空值过多    这些空值都由一个reduce处理,灰常慢
    group by    group by 维度过小,
    某值的数量过多    处理某值的reduce灰常耗时
    Count Distinct    某特殊值过多    处理此特殊值的reduce耗时
    1.2)    原因
    a)、key分布不均匀
    b)、业务数据本身的特性
    c)、建表时考虑不周
    d)、某些SQL语句本身就有数据倾斜
    1.3)    表现
    任务进度长时间维持在99%(或100%),查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成。因为其处理的数据量和其他reduce差异过大。
    单一reduce的记录数与平均记录数差异过大,通常可能达到3倍甚至更多。 最长时长远大于平均时长。
    2)    数据倾斜的解决方案
    2.1) 参数调节
    a) hive.map.aggr = true
    Map 端部分聚合,相当于Combiner
    b) hive.groupby.skewindata=true
    有数据倾斜的时候进行负载均衡,当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。
    2.2)    SQL语句调整
    a) 如何Join:
    关于驱动表的选取,选用join key分布最均匀的表作为驱动表
    做好列裁剪和filter操作,以达到两表做join的时候,数据量相对变小的效果。
    b) 大小表Join:
    使用map join让小的维度表(1000条以下的记录条数) 先进内存。在map端完成reduce.
    c) 大表Join大表:
    把空值的key变成一个字符串加上随机数,把倾斜的数据分到不同的reduce上,由于null值关联不上,处理后并不影响最终结果。
    d) count distinct大量相同特殊值
    count distinct时,将值为空的情况单独处理,如果是计算count distinct,可以不用处理,直接过滤,在最后结果中加1。如果还有其他计算,需要进行group by,可以先将值为空的记录单独处理,再和其他计算结果进行union。
    e) group by维度过小:
    采用sum() group by的方式来替换count(distinct)完成计算。
    f)特殊情况特殊处理:
    在业务逻辑优化效果的不大情况下,有些时候是可以将倾斜的数据单独拿出来处理。最后union回去。
    3)    典型的业务场景
    3.1)    空值产生的数据倾斜
    场景:如日志中,常会有信息丢失的问题,比如日志中的 user_id,如果取其中的 user_id 和 用户表中的user_id 关联,会碰到数据倾斜的问题。
    解决方法1: user_id为空的不参与关联
    select * from log a
      join users b
      on a.user_id is not null
      and a.user_id = b.user_id
    union all
    select * from log a
      where a.user_id is null;
    解决方法2 :赋与空值分新的key值
    select *
      from log a
      left outer join users b
      on case when a.user_id is null then concat(‘hive’,rand() ) else a.user_id end = b.user_id;
    结论:方法2比方法1效率更好,不但io少了,而且作业数也少了。解决方法1中 log读取两次,jobs是2。解决方法2 job数是1 。这个优化适合无效 id (比如 -99 , ’’, null 等) 产生的倾斜问题。把空值的 key 变成一个字符串加上随机数,就能把倾斜的数据分到不同的reduce上 ,解决数据倾斜问题。
    3.2)    不同数据类型关联产生数据倾斜
    场景:用户表中user_id字段为int,log表中user_id字段既有string类型也有int类型。当按照user_id进行两个表的Join操作时,默认的Hash操作会按int型的id来进行分配,这样会导致所有string类型id的记录都分配到一个Reducer中。
    解决方法:把数字类型转换成字符串类型
    select * from users a
      left outer join logs b
      on a.usr_id = cast(b.user_id as string)
    3.3)    小表不小不大,怎么用 map join 解决倾斜问题
    使用 map join 解决小表(记录数少)关联大表的数据倾斜问题,这个方法使用的频率非常高,但如果小表很大,大到map join会出现bug或异常,这时就需要特别的处理。 以下例子:
    select * from log a
      left outer join users b
      on a.user_id = b.user_id;
    users 表有 600w+ 的记录,把 users 分发到所有的 map 上也是个不小的开销,而且 map join 不支持这么大的小表。如果用普通的 join,又会碰到数据倾斜的问题。
    解决方法:
    select /*+mapjoin(x)*/* from log a
      left outer join (
        select  /*+mapjoin(c)*/d.*
          from ( select distinct user_id from log ) c
          join users d
          on c.user_id = d.user_id
        ) x
      on a.user_id = b.user_id;
    假如,log里user_id有上百万个,这就又回到原来map join问题。所幸,每日的会员uv不会太多,有交易的会员不会太多,有点击的会员不会太多,有佣金的会员不会太多等等。所以这个方法能解决很多场景下的数据倾斜问题。
    4)    总结
    使map的输出数据更均匀的分布到reduce中去,是我们的最终目标。由于Hash算法的局限性,按key Hash会或多或少的造成数据倾斜。大量经验表明数据倾斜的原因是人为的建表疏忽或业务逻辑可以规避的。在此给出较为通用的步骤:
    1、采样log表,哪些user_id比较倾斜,得到一个结果表tmp1。由于对计算框架来说,所有的数据过来,他都是不知道数据分布情况的,所以采样是并不可少的。
    2、数据的分布符合社会学统计规则,贫富不均。倾斜的key不会太多,就像一个社会的富人不多,奇特的人不多一样。所以tmp1记录数会很少。把tmp1和users做map join生成tmp2,把tmp2读到distribute file cache。这是一个map过程。
    3、map读入users和log,假如记录来自log,则检查user_id是否在tmp2里,如果是,输出到本地文件a,否则生成<user_id,value>的key,value对,假如记录来自member,生成<user_id,value>的key,value对,进入reduce阶段。
    4、最终把a文件,把Stage3 reduce阶段输出的文件合并起写到hdfs。
    如果确认业务需要这样倾斜的逻辑,考虑以下的优化方案:
    
    1、对于join,在判断小表不大于1G的情况下,使用map join
    
    2、对于group by或distinct,设定 hive.groupby.skewindata=true
    
    3、尽量使用上述的SQL语句调节进行优化
    3.11    数据膨胀导致reduce任务数不合理
    数据膨胀很多时候也会导致reduce任务个数过少。reduce数目是否合理,可以从任务的mr监控页面发现端倪。请注意job监控页面的一个参数:
    
    Reduce shuffle bytes        reduce任务读取字节数
    一般情况下,reduce任务的个数应大致等于上面这个参数的大小(请换算成GB),如果该参数大小是reduce任务数的数倍,那就意味着reduce任务数不合理。
    解决方法:
    通过设置reduce任务数提高并行度来加速执行:
    set mapred.reduce.tasks=N; //执行语句之前
    set mapred.reduce.tasks=-1; //执行语句之后恢复原状
    注意:请合理设置N的大小,最好设置为上述参数的大小。不要超过999!
    3.12    合并小文件
    文件数目过多,会给 HDFS 带来压力,并且会影响处理效率,可以通过合并 Map 和 Reduce 的结果文件来消除这样的影响:
    a)    hive.merge.mapfiles = true是否和并 Map 输出文件,默认为 True
    b)    hive.merge.mapredfiles = false是否合并 Reduce 输出文件,默认为 False
    c)    hive.merge.size.per.task = 256*1000*1000合并文件的大小
    3.13    排序优化
    Order by 实现全局排序,一个reduce实现,效率低
    Sort by 实现部分有序,单个reduce输出的结果是有序的,效率高,通常和DISTRIBUTE BY关键字一起使用(DISTRIBUTE BY关键字 可以指定map 到 reduce端的分发key)
    CLUSTER BY col1 等价于DISTRIBUTE BY col1 SORT BY col1
    3.14    动态分区
    在hive中,有时候会希望根据输入的key,把结果自动输出到不同的目录中,这可以通过动态分区来实现,就是把每一个key当作一个分区。
    如果要启动动态分区,则需要进行下面的设置
    1)    首先需要在hive语句中设置允许动态分区
    set hive.exec.dynamic.partition=true;
    set hive.exec.dynamic.partition.mode=nonstrict;
    2)    在动态分区有可能很大的情况下,还需要其他的调整
    hive.exec.dynamic.partitions.pernode 参数指的是每个节点上能够生成的最大分区,这个在最坏情况下应该是跟最大分区一样的值
    hive.exec.dynamic.partitions.partitions 参数指的是总共的最大的动态分区数
    hive.exec.max.created.files 参数指的是能够创建的最多文件数(分区一多,文件必然就多了...)
    3)    最后要注意的是select语句中要把distribute的key也select出来
    4)    适当设置reduce个数 mapred.reduce.tasks
    比如经常遇到的此问题:
    org.apache.hadoop.hive.ql.metadata.HiveException: org.apache.hadoop.ipc.RemoteException: org.apache.hadoop.hdfs.server.namenode.LeaseExpiredException: No lease on /tmp/hive-maintain/hive_2012-11-28_22-39-43_810_1689858262130334284/_task_tmp.-ext-10002/part=33436268/_tmp.000004_0 File does not exist. Holder DFSClient_attempt_201211250925_9859_m_000004_0 does not have any open files.
    可以设置
    SET hive.exec.max.dynamic.partitions=100000;
    SET hive.exec.max.dynamic.partitions.pernode=100000;
    3.15    Task任务超时,报 failed to report status for 600 seconds. Killing!
    适当设置参数mapred.task.timeout,默认600000ms,即600s,默认情况下,10分钟应该是可以了,调大后还是失败了,则请联系平台组协助解决
    3.16    OutOfMemoryError: Java heap space
    可适当调整:mapred.child.java.opts=-Xmx1024m
  • 相关阅读:
    nginx日志模块及日志定时切割
    Nginx学习笔记
    Nginx负载均衡和反向代理
    python--inspect模块
    Python--sys
    Docker 中 MySQL 数据的导入导出
    分布式监控-open-falcon
    《转载》脚本实现从客户端服务端HTTP请求快速分析
    《转载》日志大了,怎么办?用我的日志切割脚本吧!
    《MySQL》一次MySQL慢查询导致的故障
  • 原文地址:https://www.cnblogs.com/xinyumuhe/p/12165345.html
Copyright © 2011-2022 走看看