Impala只支持有限的数据隐式转换。
1、Impala不会隐式的进行String到numeric 或 Boolean类型的数据转换。
2、支持低精度到高精度数字的隐式转换,但是不支持高精度到低精度的隐式转换。
3、支持String到Timestamp的隐式转换
BIGINT
8字节整型数据类型。范围: -9223372036854775808 .. 9223372036854775807。可以通过 MIN_BIGINT()
和 MAX_BIGINT()
来查看BIGINT的边界。
语法: column_name BIGINT
类型转换: 可以自动转换为 FLOAT
和 DOUBLE
。CAST()
函数可以显式的转换为 TINYINT
、 SMALLINT
、 INT
、 STRING
和 TIMESTAMP
.
默认情况下,转换的timestamp时间默认为UTC时区。 ‑‑use_local_tz_for_unix_timestamp_conversions=true
则为本地时区。
1、CAST转换任何非数值的值为bigint时,返回NULL
2、用于分区,效率会比string更高
3、与HBASE完全兼容
BOOLEAN
TRUE
和 FALSE
两个取值范围。
语法: column_name BOOLEAN
impala不会对任何数据类型转换为布尔型。
cast非0值都是true, cast 0值都是false。
不能将 STRING
转换成 BOOLEAN
, 但是可以将 BOOLEAN
转换成 STRING
的 0 和 1。
不能用作分区键的类型。
CHAR
固定长度数据类型,如果插入数据的长度不够,将用空格填充(不会存在数据文件中,仅仅查询的时候填充);如果超出长度,会截断超出的数据。可以定义的最大长度255。
语法: column_name CHAR(length)
1)当存储的数据小于定义的数据长度时,查询结果会在末尾添加空格补齐。
2)字符开头的空格会保存在数据文件中
3)两个Char数据类型的数据,如果只是末尾空格不同,那么这两个数据的比较结果相同
4)可以作为分区键,但是效率比数值型的分区键低CHAR_LENGTH()
包含末尾空格的长度; LENGTH()
不包含末尾空格的长度。
不可用于HBASE
Parquet
和 text
格式的数据文件中, 保存超过定义长度的字符时,数据文件会保存所有的字符,但是impala查询时,会截断到定义的长度。
char
类型并没有获得impala的编译支持,所以性能比 string
和 varchar
差
DECIMAL
固定范围和精度的数据类型。
语法: DECIMAL[(precision[, scale])]
precision确定了整个数据的数字总数,范围为1到38,默认为9。
scale确定了小数位数,默认为0。
Precision决定了占用的内存大小
Text, RCFile和SequenceFile以基于ASCII格式保存:
1、开始的0不会保存,末尾的0会保存
2、小数点和负数都会多一个额外的字节
Parquet和Arvo格式的表采用二进制格式保存
关于decimal类型的计算
如果产生的精度大于38, 那么impala会截断后面的部分,但是至少保留6位小数。
使用函数时,精度和小数位的情况:
1、 SUM
精度为38,小数位与输入的列保持一致
2、 AVG
精度为38,小数位max(Scale of input column, 6)
3、 UNION
精度- max (L1, L2) + max (S1, S2),小数位max (S1, S2)
其他类型CAST为decimal时,如果精度不够,会报错。小数位不够会进行截断。
以下情况会进行DECIMAL到其它数据类型的隐式转换:
1) DECIMAL
到 double
或者 float
的转换,但是反过来不行。
2)低精度的 DECIMAL
可以隐式的转换为高精度的 DECIMAL
3)精度足够的前提下, 整数可以隐式的转换为 DECIMAL
字面量和表达式
1、没有小数位的数字。优先当做最小的整型类型,如果整型不够,则作为DECIMAL,超过DECIMAL(38, 0)的时候,当做DOUBLE类型。
2、带数字的数值。小于38位,当做DECIMAL类型;否则作为DOUBLE类型
3、Decimal支持指数计数法的数值
关于精度的修改
Impala可以通过 ALTER TABLE ... REPLACE COLUMNS
来修改列的精度。
1)对于基于文本的文件格式(Text, RCFile, SequenceFile)
* 如果修改后的精度可以匹配列中的值,则修改成功
* 如果不匹配,当 ABORT_ON_ERROR=true
修改操作会返回错误;如果 ABORT_ON_ERROR=flase
Impala会返回 NULL
值,并且给出警告信息。
2)对于二进制文件格式(Parquet和Avro)
修改语句会成功,但是在查询修改后的列的时候会抛出错误信息。因为这些文件的元数据信息是保存在文件内部的。
DOUBLE
浮点数据类型。real
别名。
语法: column_name DOUBLE
数据范围:4.94065645841246544e-324d .. 1.79769313486231570e+308的正数或者负数。
15到17个有效数据位,占8个字节。
只能通过CAST显式的将其转换为其他数据类型。
FLOAT
浮点数据类型。
语法: column_name FLOAT
数据范围:1.40129846432481707e-45 .. 3.40282346638528860e+38的正数或者负数
6到9个有效数据位,占4个字节。
可以自动的从 FLOAT
到 DOUBLE
进行转换,转换成其他数据类型需要用CAST显式转换。
INT
4字节的整型数字。INTEGER
别名。
语法: column_name INT
数据范围: -2147483648 .. 2147483647
可以自动的转换为 BIGINT
、 DOUBLE
和 FLOAT
,其他数据类型需要用CAST显式转换。
可以通过 min_int()
和 max_int()
来检查int的数据边界。
把一个非数字的值转换为INT, 会返回空
SMALLINT
2字节的整型数值。
语法: column_name SMALLINT
数据范围:-32768 .. 32767
可以自动的转换为 BIGINT
、 INT
和浮点数据类型,其他数据类型需要用CAST显式转换。
可以通过 min_smallint()
和 max_smallint()
来查看数据边界。
把一个非数字的值转换为SMALLINT, 会返回空。
TINYINT
1字节的整型数值
语法: column_name TINYINT
数据范围:128 .. 127
可以自动的转换为 SMALLINT
、 BIGINT
、 INT
和浮点数据类型,其他数据类型需要用CAST显式转换。
可以通过 min_tinyint()
和 max_tinyint()
来查看数据边界。
把一个非数字的值转换为TINYINT, 会返回空。
STRING
string相较于varchar和char拥有更好的性能。
语法: column_name STRING
string的长度需要考虑以下因素:
1)包含string的数据行,最大2GB
2)Parquet文件,STRING最大1GB
3)小于等于32KB的字符串查询不会存在显著的性能问题和内存问题,当大于32KB时,性能会显著的下降。
4)行大小会受到 spill-to-disk
支持的限制:
a. hash-join中来着右边的行
b. spills to disk的hash-join两边的行
c. 行被没有限制的 `SORT` 操作排序
d. 分组聚合中
CDH 5.12以及以下版本限制是8MB,以上版本受 `MAX_ROW_SIZE` 的查询参数控制,默认512KB
字符集:
为了支持所有的impala子系统,字符集被限制为ASCII。虽然也可以保存UTF-8的字符集,但是在部分情况下不能保证正常工作:
1)字符串操作函数
2)比较操作
3) ORDER BY
子句
4)作为分区键
类型转换
1)impala不会自动的转换string为数值类型,可以自动转换为 TIMESTAMP
2)通过CAST()强制转换成数值类型
3)cast无法转换string为boolean
4)可以cast一个boolean为string,true返回1,false返回0
TIMESTAMP
保存日期和时间值,没有时区信息。占用16个字节。
语法:
1 | column_name TIMESTAMP |
数据范围: 1400-01-01 to 9999-12-31, 超出范围返回NULL
INTERVAL表达式:
timestamp_value + INTERVAL 3 WEEKS - INTERVAL 1 DAY + INTERVAL 10 MICROSECONDS
- YEAR[S]
- MONTH[S]
- WEEK[S]
- DAY[S]
- HOUR[S]
- MINUTE[S]
- SECOND[S]
- MILLISECOND[S]
- MICROSECOND[S]
- NANOSECOND[S]
时区:
默认情况下,impala存储和解释的timestamp为UTC时区。
当设置启动参数 -use_local_tz_for_unix_timestamp_conversions
为 TRUE
时,将视作本地时区。
Impala和HIVE对时区的处理
根据文件格式的不同,处理方式不一样
1)Text
Impala和Hive处理相同,不会进行时区转换。
2)Parquet
当Hive写数据文件时,会把本地机器的时区时间转换成UTC时间进行写入。但是Impala不会,默认情况下读写都不会进行时区的转换。这种处理差异,可能会导致Hive和Impala的查询结果不一致。
为了解决不兼容问题或者必须通过编码处理,可以通过设置以下参数来避免:
• --use_local_tz_for_unix_timestamp_conversions=true
• --convert_legacy_hive_parquet_utc_timestamps=true
这个参数可以使impala识别到Hive写入的数据,并执行UTC到local-time-zone的转换
类型转换
字符串可以自动的转换成timestamp类型。当转换一个不能识别的字符串时,会返回空值。
VARCHAR
可变长度的字符类型,最大长度为65,535。当超出范围的时候会被截断。
语法: column_name VARCHAR(max_length)
Complex Types
Impala 2.3开始,Impala支持 ARRAY、MAP、STRUCT复杂类型,暂不支持HIVE的UNION类型。目前Impala只能查询其他组件产生的复杂数据类型列。
概述
Array
和 Map
保存任意数量相同类型的元素;Struct
将固定数量的元素保存成一个元素,每个 field
的类型可以不同。
所有的复合数据类型可以嵌套其他复合数据类型,最多可以嵌套100层。
使用场景
1)由Hive或者其他组件产生的复杂数据类型列,将其转换成Parquet类型的数据文件,然后在Impala中进行处理。
2)由非SQL的编程语言或者NoSQL系统产生的类似复杂数据类型的数据。
3)在对多表的分析处理中,可以从数据本地化中获得巨大收益。将相关数据打包到复杂数据类型中,可以避免在join查询时网络传输带来的性能消耗。
使用的注意事项
1、与传统数据仓库模式的差异
传统的数据仓库在处理相关数据时一般有两种方案:
1)将其拆分到不同的规范化表中,这样可以避免重复数据,但是join操作会带来比较大的性能消耗
2)同一个表中增加列或者行来存储,这样性能比较好,但是可能带来重复数据的存储,以及在不确定数据量的情况,不好确定宽表的列数量。
复杂数据类型在性能和存储空间上提供了一个折中的选项,在物理上,相关的数据会在一个数据块上,避免了join带来的网络消耗。
2、物理存储
物理上,每行标量数据类型和复杂数据类型的列都存储在相邻位置,以确保他们能在同一主机上处理,避免数据传输带来的消耗。得益于Parquet文件的列式存储,对复杂数据类型的访问,也只会获取指定标量列的结果,避免了大量的IO消耗。
1)STRUCT数据类型的每个filed都像列一样存储,所有标量值都彼此相邻,并使用Parquet的space-saving技术对其进行编码、压缩。
2)ARRAY数据类型,所有值都相邻存储,使用伪列 ITEM
表示。 POS
伪列并不会进行物理的存储。
3)MAP数据类型,所有的伪列 KEY
和 VALUE
都存储在相邻位置。
3、支持的文件格式
目前仅Parquet文件格式支持复杂数据类型。对于其他文件格式,如果包含嵌套的复杂数据类型,查询的时候会报错。甚至DROP掉这个列,在查询的时候依然会报错。唯一的列外就是可以在RCFILE上执行count(*)的操作。
4、复杂数据类型和规范表的选择
选择拆分为多个规范化表或者使用复杂数据类型,取决于很多因素:
1)如果是有传统数据库或者数仓背景,已有的工具更擅长处理规范化表,这个时候就更加倾向选择拆分为规范表。
2)复杂数据类型可以简化与Python、scala和Java的数据交互
3)现有的基础架构设施中产生的数据包含复杂类型结构,使用复杂数据类型可以简化这些数据的操作。
4)当数据中部分列需要变更时,包含复杂数据类型的列需要全部重新加载。如果经常涉及到这样的数据变更,拆分为规范化表更合适。
5)Parquet的列式存储、相邻数据存储在同一数据块、避免join操作,这些优势可以让查询性能更好。但是包含复杂数据类型的表会让同一数据块中包含更少的行,如果很少使用到复杂数据类型的列,那么应该避免这种存储方式。
5、与Hive中复杂数据类型的差异
1)由于Impala中的 STRUCT
列包含用户自定义的filed名称,Hive在往impala表中写入STRUCT列时使用 NAMED_STRUCT
函数进行构造。
2)Impala暂不支持hive中的 UNION
数据类型。
3)Impala中使用点和伪列名称或者field名称搭配join来引用复杂数据类型,HIVE中使用 LATERAL VIEW
和 EXPLOED()
来展开数据。
6、复杂类型的一些限制
1)只能用在Parquet格式的表或者分区中。并且Impala不能向其中写入数据。
2)不能作为分区列
3)不能作为 ORDER BY
, HAVING
, GROUP BY
和 WHERE
子句中,必须引用其中的标量值。
4)复杂数据类型的嵌套,最多100层
5)列名的定义最多4000个字符
6)使用小的或者中等大小的列,这些数据一般放在同一个数据块中,而HDFS的数据块大小一般为256MB到1GB
7)包含复杂数据类型列的表会增加额外的查询开销,哪怕查询结果没有查询复杂数据类型列
8) COMPUTE STATS
不会收集复杂数据类型列的统计信息
9)内置函数和自定义函数都不接受复杂数据类型列作为参数
ARRAY Complex Type
存放任意数量的有序元素。其中存储的可以是基本数据类型,也可是复杂数据类型。
语法
1 | column_name ARRAY < type > |
type可以是其他标量类型或者复合类型。使用 ITEM
or POS
伪列来访问其中的数据。
当Array中的数据是基本数据类型的时候,可以对其中的元素使用聚合函数,例如 count
sum
max
等。
1)例子:建表
1 | CREATE TABLE array_demo |
2)例子:查看表和复杂数据类型的结构
1 | DESCRIBE array_demo; |
3)例子:查询
1 | -- 包含基本数据类型的Array |
MAP
保存任意数量的key-value数据对。其中key必须是基本数据类型,value可以是基本数据类型也可以是复杂数据类型。Impala不会对key进行强制性的唯一约束。
语法:
1 | column_name MAP < primitive_type, type > |
建表示例
1 | create TABLE map_demo |
STRUCT
逻辑上把多个field的数据放在一起。通常作为ARRAY或者MAP的值。
语法:
1 | column_name STRUCT < name : type [COMMENT 'comment_string'], ... > |
建表示例
1 | CREATE TABLE struct_demo |
查询示例
1 | SELECT id, employee_info.id AS employee_id FROM struct_demo; |