Impala SQL 语言元素(翻译)

摘要: http://www.cloudera.com/content/cloudera-content/cloudera-docs/Impala/latest/Installing-and-Using-Impala/ciiu_langref_sql.html

Impala SQL 语言元素(Elements)

Impala SQL 方言支持一组标准元素(a range of standard elements),加上许多大数据方面的扩展,用于数据加载和数据仓库方面。

Impala SQL 语言元素(翻译)  注意:

在之前的 Impala beta 版中,在 impala-shell 中每一语句结束时的分号是可选的。现在 impala-shell 支持多行命令,以便于从脚本文件中复制粘贴代码,这样每一语句结束时的分号是必需的。

下面章节演示了 Impala 中 SQL 语言的主要语句、子句以及其他元素。

继续阅读:

 

ALTER TABLE 语句

ALTER TABLE 语句用来修改现有表的结构或属性。在 Impala 里,这是一个逻辑操作,更新了 Impala 和 Hive 共用的 metastore 数据库中表的元数据; ALTER TABLE 语句不会对实际的数据文件进行重写、移动等操作。因此,你可能需要相应的物理文件系统操作才能实现移动数据文件到不同的 HDFS 目录,重写数据文件来包含其他字段,或转换成不同的文件格式。

重命名表:

ALTER TABLE old_name RENAME TO new_name;

对于内部表,这一操作实际地修改了包含数据文件的 HDFS 目录名;原始目录将不再存在。通过修改表名前面的数据库名,你可以把一个数据库中的内部表(包括对应的数据目录)移动到另一个数据库。例如:

create database d1;
create database d2;
create database d3;
use d1;
create table mobile (x int);
use d2;
-- 移动其他数据库中的表到当前数据库
alter table d1.mobile rename to mobile;
use d1;
-- 移动一个数据库中的表达哦另一个数据库
alter table d2.mobile rename to d3.mobile;

修改 Impala 查找表的相关数据文件的物理位置:

ALTER TABLE table_name SET LOCATION 'hdfs_path_of_directory';

指定的路径是数据文件所在的完整路径,或者是不存在被创建的路径。Impala 不会创建该表名下面的额外子目录。Impala 不会移动任意数据文件到新位置,也不会修改这一目录下现存的数据文件。

修改 TBLPROPERTIES 和 SERDEPROPERTIES 列的键值对:

ALTER TABLE table_name SET TBLPROPERTIES ('key1'='value1', 'key2'='value2', ...);
ALTER TABLE table_name SET SERDEPROPERTIES ('key1'='value1', 'key2'='value2', ...);

  

TBLPROPERTIES 子句是将任意用户指定数据项与特定表关联起来的主要方法(The TBLPROPERTIES clause is primarily a way to associate arbitrary user-specified data items with a particular table)。SERDEPROPERTIES 子句设置表如何读写,在 Hive 中许多情况下需要,实际在 Impala 中未使用(The SERDEPROPERTIES clause sets up metadata defining how tables are read or written, needed in some cases by Hive but not actually used by Impala)。参考 CREATE TABLE Statement 了解这些子句的详细信息。参考 Setting Statistics Manually through ALTER TABLE 中的使用表属性来微调相关表统计信息的性能的例子(for an example of using table properties to fine-tune the performance-related table statistics)。

重组表中的列:

ALTER TABLE table_name ADD COLUMNS (column_defs);
ALTER TABLE table_name REPLACE COLUMNS (column_defs);
ALTER TABLE table_name CHANGE column_name new_name new_spec;
ALTER TABLE table_name DROP column_name;

其中 column_spec 与 CREATE TABLE 语句中相同:列名,列数据类型,以及可选的列备注。你可以一次添加多个列。无论是添加单个列还是多个列,都需要用括号括起来。当替换列时,原有列的定义都被废弃。你可能会在收到一组新的有不同数据类型或不同顺序的列的数据文件时使用这一技术(数据文件会被保留,因此当新列与旧列不兼容时,需要在执行进一步的查询前,使用 INSERT OVERWRITE 或 LOAD DATA OVERWRITE 语句替换所有的数据)。

你可以使用 CHANGE 子句重命名某一个列,或转换现存的列为其他类型,例如在 STRING 和 TIMESTAMP 之间转换,或者在 INT 与 BIGINT 之间转换。一次只能删除一个列;想要删除多个列,需要执行多次 ALTER TABLE 语句,或者在单个  ALTER TABLE ... REPLACE COLUMNS 语句中定义一组新的列。

修改 Impala 中表期望的文件格式(To change the file format that Impala expects table data to be in):

ALTER TABLE table_name SET FILEFORMAT { PARQUET | PARQUETFILE | TEXTFILE | RCFILE | SEQUENCEFILE }

因为本操作只是修改表的元数据,对现存的数据,你必须使用 Impala 之外的 Hadoop 技术对已有的数据进行转换。之后再在 Impala 中使用 INSERT 语句创建的数据将使用新的格式。你不能指定文本文件的分隔符;文本文件的分隔符必须是逗号。

为了添加或删除表的分区, 表必须已经是分区表(也就是说,使用带 PARTITIONED BY 子句创建的表)。分区是一个 HDFS 中的实际目录,目录名包含特定列的值(partition key,分区键)。假如必要,Impala 的 INSERT 语句会创建分区,因此 ALTER TABLE ... ADD PARTITION 语句的主要用途是通过移动或复制已有的数据文件到分区对应的 HDFS 目录来导入数据。DROP PARTITION 子句用于删除一组指定分区键值对应的 HDFS 目录和对应的数据文件;例如,假如你总是分析最近 3 个月数据的价值,在每个月初你就可以删除掉不再需要的最老的那个分区的数据。删除分区会减少表相关的元数据数量,减轻计算查询计划的复杂度,从而可以简化和提升分区表的查询速度,特别是连接查询。下面展示了 ADD PARTITION 和 DROP PARTITION 子句。

-- 创建一个空的分区模式的表
create table part_t (x int) partitioned by (month string);
-- 创建一个空分区,下面将从其他源复制数据文件到这个分区
alter table part_t add partition (month='January');
-- 变更相关数据后,执行 REFRESH 语句使得数据对 Impala 可见
refresh part_t;
-- 然后,添加下一月份
alter table part_t add partition (month='February');
-- 现在不再需要一月份数据
alter table part_t drop partition (month='January');
-- 假如表是根据月份、年份分区,执行类似语句:
-- alter table part_t drop partition (year=2003,month='January');
-- 这将需要 12 个 ALTER TABLE 语句来删除 2003 整年的数据

分区键的值可以是任意常数表达式,不需要引用标中的列(The value specified for a partition key can be an arbitrary constant expression, without any references to columns).例如:

alter table time_data add partition (month=concat('Decem','ber'));
alter table sales_data add partition (zipcode = cast(9021 * 10 as string));

使用注意:

在 ALTER TABLE 语句中,必须包括所有的分区列(Whenever you specify partitions in an ALTER TABLE statement, you must include all the partitioning columns in the specification)。

对于内部表(Impala 管理表)和外部表(数据文件在任意位置)来说,之前的绝大多数操作是一致的。唯一的列外是重命名表;对外部表来说,相关的数据目录不会被重命名或移动。

假如为了负载均衡的原因,在 impala-shell 会话中连接到了不同的 Impala 节点,可以启用 SYNC_DDL 查询选项以使得每一 DDL 语句在新的或修改的元数据被所有 Impala 节点接受前等待,直到都被接受后才返回。参考 SYNC_DDL 了解详细信息。

Impala SQL 语言元素(翻译)  注意:

重组表和其关联的数据文件的另一种方法是使用 CREATE TABLE 语句创建一个与原始表不同的表,然后使用 INSERT 语句复制转换或重新排序的数据到新表。ALTER TABLE 的优势是避免了数据文件的重复复制,允许你使用熟悉的 Hadoop 技术以一种节省空间的方式来重组巨大容量的数据。

语句类型: DDL

ALTER VIEW 语句

修改视图里的查询,或相关的数据库和/或视图的名称。

因为视图是一种纯逻辑结构(一个查询的别名)没有实际的数据,ALTER VIEW 只执行 metastore 数据库中元数据的修改,不涉及 HDFS 中的任意数据文件。

ALTER VIEW [database_name.]view_name AS select_statement
ALTER VIEW [database_name.]view_name RENAME TO [database_name.]view_name

假如为了负载均衡的原因,在 impala-shell 会话中连接到了不同的 Impala 节点,可以启用 SYNC_DDL 查询选项以使得每一 DDL 语句在新的或修改的元数据被所有 Impala 节点接受前等待,直到都被接受后才返回。参考 SYNC_DDL 了解详细信息。

例子:

create table t1 (x int, y int, s string);
create table t2 like t1;
create view v1 as select * from t1;
alter view v1 as select * from t2;
alter view v1 as select x, upper(s) s from t2;

执行 DESCRIBE FORMATTED 语句来查看视图的定义,这将显示原始 CREATE VIEW 中的查询:

[localhost:21000] > create view v1 as select * from t1;
[localhost:21000] > describe formatted v1;
Query finished, fetching results ...
+------------------------------+------------------------------+----------------------+
| name | type | comment |
+------------------------------+------------------------------+----------------------+
| # col_name | data_type | comment |
| | NULL | NULL |
| x | int | None |
| y | int | None |
| s | string | None |
| | NULL | NULL |
| # Detailed Table Information | NULL | NULL |
| Database: | views | NULL |
| Owner: | cloudera | NULL |
| CreateTime: | Mon Jul 08 15:56:27 EDT 2013 | NULL |
| LastAccessTime: | UNKNOWN | NULL |
| Protect Mode: | None | NULL |
| Retention: | 0 | NULL |
| Table Type: | VIRTUAL_VIEW | NULL |
| Table Parameters: | NULL | NULL |
| | transient_lastDdlTime | 1373313387 |
| | NULL | NULL |
| # Storage Information | NULL | NULL |
| SerDe Library: | null | NULL |
| InputFormat: | null | NULL |
| OutputFormat: | null | NULL |
| Compressed: | No | NULL |
| Num Buckets: | 0 | NULL |
| Bucket Columns: | [] | NULL |
| Sort Columns: | [] | NULL |
| | NULL | NULL |
| # View Information | NULL | NULL |
| View Original Text: | SELECT * FROM t1 | NULL | | View Expanded Text: | SELECT * FROM t1 | NULL |
+------------------------------+------------------------------+----------------------+
Returned 29 row(s) in 0.05s

语句类型: DDL

AVG 函数

返回一组数字的均值的聚合函数。它唯一的参数是一个数值列、或者基于列返回数值的函数或表达式(Its single argument can be numeric column, or the numeric result of a function or expression applied to the column value)。指定列中值为 NULL 的行将被忽略。假如表为空,或者输入 AVG 的值都是 NULL,则 AVG 返回 NULL。

当查询包含 GROUP BY 子句,返回每一个分组组合的一个值。

返回类型: DOUBLE

例子:

-- 计算所有非空行的均值
insert overwrite avg_t values (2),(4),(6),(null),(null);
-- 上面表中的均值是 4: (2+4+6) / 3. 两个 NULL 值被忽略
select avg(x) from avg_t;
-- 计算特定行的均值(Average only certain values from the column)
select avg(x) from t1 where month = 'January' and year = '';
-- 在计算均值前进行计算
select avg(x/3) from t1;
-- 在计算均值前对列进行函数运算
-- 这里把所有 NULL 的行替换为 0
-- 这样值为 NULL 的行也会作为均值计算的因子
select avg(isnull(x,0)) from t1;
-- 对 string 列使用某些返回值为数字的函数,然后计算均值
-- 假如某行 s 的值包含 NULL,则 length(s) 函数也返回 NULL,该行被忽略
select avg(length(s)) from t1;
-- 也可以与 DISTINCT 和/或 GROUP BY 组合使用
-- 返回多于一个的结果
select month, year, avg(page_visits) from web_stats group by month, year;
-- 在执行计算前过滤重复的值
select avg(distinct x) from t1;
-- 执行计算后过滤输出的值
select avg(x) from t1 group by y having avg(x) between 1 and 20;

BETWEEN 操作符

在 WHERE 子句中,将表达式与下限和上限比较。当表达式大于等于下限,并且小于等于上限,则表达式比较成功。假如上限下限互换,也就是说下限大于上限,那么就不匹配任何值。

语法: expression BETWEEN lower_bound AND upper_bound

数据类型: 通常使用数字类型。适用于任何类型但不是很实用的 BOOLEAN(Works with any data type, although not very practical for BOOLEAN values)。 (BETWEEN false AND true 会匹配所有的 BOOLEAN 值)。必要时使用 CAST() 函数来确保下限和上限值是兼容的数据类型。假如必要的时候调用 string 或 date/time 函数来提取或转换相关的比较部分,特别是值可以转换成数字的时候。

使用注意:使用短字符串操作数时要当心(Be careful when using short string operands)。以上限的字符串开始的长字符串将不被包含,因为它被认为是大于上限(A longer string that starts with the upper bound value will not be included, because it is considered greater than the upper bound)。例如,BETWEEN 'A' and 'M' 将不会匹配字符串 'Midway'。假如必要,使用例如 upper(), lower(), substr(), trim(), 等等函数以确保比较如预期执行。

例子:

-- 返回1到6月的值,包括1跟6月.
select c1 from t1 where month between 1 and 6; -- 返回以'A' 到 'M' 开头的名字
-- 只检测第一个字符以确保所有以 'M' 开头的名称符合
-- 进行大小写敏感的比较以配合不同大小写约定的名称(Do a case-insensitive comparison to match names with various capitalization conventions)
select last_name from customers where upper(substr(last_name,1,1)) between 'A' and 'M'; -- 返回每个月第一周的数据
select count(distinct visitor_id)) from web_traffic where dayofmonth(when_viewed) between 1 and 7;

BIGINT 数据类型

8字节的整数类型,用于 CREATE TABLE 和 ALTER TABLE 语句。

范围: -9223372036854775808 .. 9223372036854775807。没有无符号子类型。

转换: Impala 自动转换为浮点类型(FLOAT or DOUBLE)。 使用 CAST() 函数转换成 TINYINT, SMALLINT, INT, STRING, or TIMESTAMP。数值 N 转换成 TIMESTAMP 时,是转换成从 1970年1月1日开始的 N 秒。

相关信息: INT Data TypeSMALLINT Data TypeTINYINT Data TypeMathematical Functions

BOOLEAN 数据类型

用于 CREATE TABLE 和 ALTER TABLE 语句的数据类型,表示一个单一的 true/false 的选择。

范围: TRUE or FALSE。不要使用引号引起 TRUE 和 FALSE 的字符值。你可以使用大写、小写或混合格式的值。表中返回的值都是小写的 true 或 false。

转换: Impala 不会自动转换其他类型为 BOOLEAN。可以使用 CAST() 转换任意 integer 或 float-point 类型为 BOOLEAN: 0 表示 false,其他非零值转化为 true。STRING 不能转换为 BOOLEAN,尽管 BOOLEAN 可以转换为 STRING,其中 true 对应 '1' 而 false 对应 '0'。

相关信息: Conditional Functions

注释

Impala 支持大家熟悉的 SQL 注释风格:

  • 从 -- 开始的到行尾都被作为注释而忽略。这种类型的注释可以单独出现在一行上,或者所有或部分语句之后
  • 从 /* 开始到下一个 */ 结束的文字都被作为注释而忽略。这种类型的注释可以跨越多行。这种类型的注释可以在语句中或者语句之前、之后出现在一行或多行

例如:

-- 本行是表的注释
create table ...; /*
本还是查询的多行注释
*/
select ...; select * from t /* 这是查询的嵌入式注释 */ where ...; select * from t -- 这是多行命令中的尾部注释
where ...;

比较操作

Impala 支持大家熟悉的比较操作用于检测相等、存在并为列数据类型排序:

  • =, !=, <>
  • IS NULL, IS NOT NULL
  • <, <=, >, >=
  • BETWEEN lower_bound AND upper_bound
  • LIKEREGEXP (仅支持STRING)

COMPUTE STATS 语句

采集关于表和相关列与分区中数据的数据量和分布(Gathers information about volume and distribution of data in a table and all associated columns and partitions)。这些信息被存放在 metastore 数据库中,被 Impala 用于帮助优化查询。假设 Impala 可以判断表的大小,有许多或几个的不同的值,那么它可以为连接查询或插入操作组织适当的并行操作。了解这一语句采集的几种信息,参见 Table Statistics

使用注意:

原来 Impala 依靠用户运行 Hive ANALYZE TABLE 语句,但这一方法采集的统计信息被证明是缓慢和不可靠的。Impala 的 COMPUTE STATS 语句是从底层向上构建,以提高可用性和用户友好度。你可以运行一个单独的 Impala COMPUTE STATS 语句来采集包括 table 和 column 的统计信息,而不是为表和列的统计信息分别运行 Hive ANALYZE TABLE 语句。

COMPUTE STATS 也可以采集 HBase 表的信息。采集的 HBase 表的统计信息与 HDFS-backed 表的有所不同,但当 HBase 表执行连接查询时,统计信息仍被用于优化。

相关信息参见 SHOW StatementTable Statistics, and Column Statistics

例子:

本例中展示了 T1 和 T2 两个表,其中 T1.ID 和 T2.PARENT 存在父子关系,有少量的不同的值链接。T1 是小表,而 T2 大概有 100K 行。最初,统计信息包括物理度量如文件的数量,总大小,以及定长列如 INT 类型的大小度量。未知值表示为 -1。为每个表运行 COMPUTE STATS 之后,SHOW STATS 语句中有更多信息可用。假如你运行一个涉及这两个表的连接查询,你需要统计这两个表以获得最优化的查询。

[localhost:21000] > show table stats t1;
Query: show table stats t1
+-------+--------+------+--------+
| #Rows | #Files | Size | Format |
+-------+--------+------+--------+
| -1 | 1 | 33B | TEXT |
+-------+--------+------+--------+
Returned 1 row(s) in 0.02s
[localhost:21000] > show table stats t2;
Query: show table stats t2
+-------+--------+----------+--------+
| #Rows | #Files | Size | Format |
+-------+--------+----------+--------+
| -1 | 28 | 960.00KB | TEXT |
+-------+--------+----------+--------+
Returned 1 row(s) in 0.01s
[localhost:21000] > show column stats t1;
Query: show column stats t1
+--------+--------+------------------+--------+----------+----------+
| Column | Type | #Distinct Values | #Nulls | Max Size | Avg Size |
+--------+--------+------------------+--------+----------+----------+
| id | INT | -1 | -1 | 4 | 4 |
| s | STRING | -1 | -1 | -1 | -1 |
+--------+--------+------------------+--------+----------+----------+
Returned 2 row(s) in 1.71s
[localhost:21000] > show column stats t2;
Query: show column stats t2
+--------+--------+------------------+--------+----------+----------+
| Column | Type | #Distinct Values | #Nulls | Max Size | Avg Size |
+--------+--------+------------------+--------+----------+----------+
| parent | INT | -1 | -1 | 4 | 4 |
| s | STRING | -1 | -1 | -1 | -1 |
+--------+--------+------------------+--------+----------+----------+
Returned 2 row(s) in 0.01s
[localhost:21000] > compute stats t1;
Query: compute stats t1
+-----------------------------------------+
| summary |
+-----------------------------------------+
| Updated 1 partition(s) and 2 column(s). |
+-----------------------------------------+
Returned 1 row(s) in 5.30s
[localhost:21000] > show table stats t1;
Query: show table stats t1
+-------+--------+------+--------+
| #Rows | #Files | Size | Format |
+-------+--------+------+--------+
| 3 | 1 | 33B | TEXT |
+-------+--------+------+--------+
Returned 1 row(s) in 0.01s
[localhost:21000] > show column stats t1;
Query: show column stats t1
+--------+--------+------------------+--------+----------+----------+
| Column | Type | #Distinct Values | #Nulls | Max Size | Avg Size |
+--------+--------+------------------+--------+----------+----------+
| id | INT | 3 | 0 | 4 | 4 |
| s | STRING | 3 | 0 | -1 | -1 |
+--------+--------+------------------+--------+----------+----------+
Returned 2 row(s) in 0.02s
[localhost:21000] > compute stats t2;
Query: compute stats t2
+-----------------------------------------+
| summary |
+-----------------------------------------+
| Updated 1 partition(s) and 2 column(s). |
+-----------------------------------------+
Returned 1 row(s) in 5.70s
[localhost:21000] > show table stats t2;
Query: show table stats t2
+-------+--------+----------+--------+
| #Rows | #Files | Size | Format |
+-------+--------+----------+--------+
| 98304 | 1 | 960.00KB | TEXT |
+-------+--------+----------+--------+
Returned 1 row(s) in 0.03s
[localhost:21000] > show column stats t2;
Query: show column stats t2
+--------+--------+------------------+--------+----------+----------+
| Column | Type | #Distinct Values | #Nulls | Max Size | Avg Size |
+--------+--------+------------------+--------+----------+----------+
| parent | INT | 3 | 0 | 4 | 4 |
| s | STRING | 6 | 0 | -1 | -1 |
+--------+--------+------------------+--------+----------+----------+
Returned 2 row(s) in 0.01s

COUNT 函数

返回满足一定条件记录的行数或非空行的行数的聚合函数:

  • COUNT(*) 统计包含 NULL 值的所有行数
  • COUNT(column_name) 只计算该列中值非空的行数
  • 可以结合使用 COUNT 与 DISTINCT 在计算前消除重复值,并计算多个列组合的值

当查询中包含 GROUP BY 子句时,we

Return type: BIGINT

Examples:

-- 表中有多少行,不关心是否有 NULL 值
select count(*) from t1;
-- 表中有多少 c1 列的值不为空的行
select count(c1) from t1;
-- 计算满足条件的行数
-- 另外, * 包括 NULL, 因此 COUNT(*) 可能比 COUNT(col) 的值大.
select count(*) from t1 where x > 10;
select count(c1) from t1 where x > 10;
-- 可以与 DISTINCT 和/或 GROUP BY 操作联合使用
-- 联合使用 COUNT 和 DISTINCT 查找唯一值的个数
-- 在 COUNT(DISTINCT ...) 语法中必须使用列名而不是 *
-- c1 包含空值的行不会统计
select count(distinct c1) from t1;
-- c1 或 c2 中包含空值的每一行都不会统计(Rows with a NULL value in _either_ column are not counted)
select count(distinct c1, c2) from t1;
-- 返回多个结果
select month, year, count(distinct visitor_id) from web_stats group by month, year;

CREATE DATABASE 语句

在 Impala 里,数据库是:

  • 逻辑结构,包含在自己命名空间下组合在一起的相关的表(A logical construct for grouping together related tables within their own namespace)。你可以每个应用、一组相关的表或一轮实验都使用单独的数据库(You might use a separate database for each application, set of related tables, or round of experimentation)
  • 物理结构,对应 HDFS 中的目录树(A physical construct represented by a directory tree in HDFS)。表(内部表),分区,和数据文件都在该目录下分配。你可以备份、计算空间使用情况、或使用 DROP DATABASE 语句删除它(目录为空时)

创建数据的语法如下:

CREATE (DATABASE|SCHEMA) [IF NOT EXISTS]database_name[COMMENT 'database_comment']
[LOCATION hdfs_path];

数据库实际对应 HDFS 中 Impala 数据目录中的目录,目录名为数据库名+.db。假如 HDFS 中相关目录不存在则自动创建。所有数据库和它们相关的目录是顶层对象,没有逻辑或物理嵌套(All databases and their associated directories are top-level objects, with no physical or logical nesting)。

使用注意:

当创建数据库之后,在 impala-shell 会话中,使用 USE 语句切换为当前数据库。你可以不加数据库名前缀访问当前数据库中的表。

当第一次使用 impala-shell 连接到 Impala,默认的开始数据库是 (在执行任意的 CREATE DATABASE 或 USE 语句前) default。

当创建数据库之后,你的 impala-shell 会话或其他的连接到相同节点的 impala-shell 会话可以立即访问该数据库。当通过其他节点的 Impala 守护进程访问该数据库时,应先执行 INVALIDATE METADATA 语句

假如为了负载均衡的原因,在 impala-shell 会话中连接到了不同的 Impala 节点,可以启用 SYNC_DDL 查询选项以使得每一 DDL 语句在新的或修改的元数据被所有 Impala 节点接受前等待,直到都被接受后才返回。参考 SYNC_DDL 了解详细信息。

例子:

create database first;
use first;
create table t1 (x int); create database second;
use second;
-- 数据库中的表以数据库名作为它的命名空间
-- 不同的数据库中可以有同名的表
create table t1 (s string); create database temp;
-- 创建数据库后没有使用 USE 语句切换数据库,而是通过数据库名前缀来标识表
create table temp.t2 (x int, y int);
use database temp;
create table t3 (s string);
-- 当数据库被 USE 语句选中时,无法删除
drop database temp; ERROR: AnalysisException: Cannot drop current default database: temp -- The always-available database 'default' is a convenient one to USE.
use default;
-- 删除数据库可以快速删除下面的所有表
drop database temp;

语句类型: DDL

CREATE FUNCTION 语句

创建一个用户定义函数(UDF),当执行 SELECT 或 INSERT 操作时,可以实现自定义的逻辑。

语法:

创建标量函数(scalar UDF)与聚合函数(UDA)的语法不同。标量函数每行调用一次,执行单个函数(which is called once for each row and implemented by a single function),而用户定义聚合函数执行多个函数跨越多组行的中间结果(which is implemented by multiple functions that compute intermediate results across sets of rows)。

执行 CREATE FUNCTION 语句创建标量函数:

CREATE FUNCTION [IF NOT EXISTS] [db_name.]function_name([arg_type[,arg_type...])
RETURNS return_type LOCATION 'hdfs_path'
SYMBOL='symbol_or_class'

执行 CREATE AGGREGATE FUNCTION 语句创建 UDA:

CREATE [AGGREGATE] FUNCTION [IF NOT EXISTS] [db_name.]function_name([arg_type[,arg_type...])
RETURNSreturn_typeLOCATION 'hdfs_path'
[INIT_FN='function]
UPDATE_FN='function MERGE_FN='function [FINALIZE_FN='function]

标量与聚合函数:

最简单的一种用户定义函数每次调用时返回一个标量值,典型的是结果集中每一行返回一个值。这种普通的函数通常称为 UDF。用户定义聚合函数(UDA) 是一种特别的基于多行的内容产生单一值的 UDF。通常 UDA 会与 GROUP BY子句联合使用,压缩大的结果集到一个小的结果集,甚至对整表产生一个概述列(This general kind of function is what is usually meant by UDF. User-defined aggregate functions (UDAs) are a specialized kind of UDF that produce a single value based on the contents of multiple rows. You usually use UDAs in combination with a GROUP BY clause to condense a large result set into a smaller one, or even a single row summarizing column values across an entire table)。

使用 CREATE AGGREGATE FUNCTION 语句创建 UDA。 仅当创建 UDA 而不是 标量 UDF 时,INIT_FN, UPDATE_FN, MERGE_FN, FINALIZE_FN, INTERMEDIATE 子句被使用。

使用 *_FN 子句指定的函数在函数处理的不同阶段进行调用。

  • Initialize: 在 INIT_FN 子句中指定的函数完成初始化设置,例如初始化内部数据结果的成员变量。This function is often a stub for simple UDAs. 你可以忽略这一子句则会执行一个默认(无操作)函数操作。
  • Update: 在 UPDATE_FN 子句中指定的函数会在原始结果集的每一行调用一次,也就是说,在执行 GROUP BY 子句之前被执行。 对于 GROUP BY 子句返回的每一个不同的值,会调用一个单独的函数实例(A separate instance of the function is called for each different value returned by the GROUP BY clause)。 The final argument passed to this function is a pointer, to which you write an updated value based on its original value and the value of the first argument.
  • Merge: 在 MERGE_FN 子句中指定的函数被调用任意次数,与不同节点或不同线程的 Impala 并行读取和处理数据文件产生的中间结果有关。The final argument passed to this function is a pointer, to which you write an updated value based on its original value and the value of the first argument.
  • Finalize: 在 FINALIZE_FN 子句执行释放之前的 UDF 申请的资源,例如释放内存,关闭之前打开的文件句柄,诸如此类。This function is often a stub for simple UDAs. 你可以忽略这一子句则会执行一个默认(无操作)函数操作。

假如你对每一个相关的函数使用一致的命名约定,Impala 基于最初的子句可以自动的确定函数名称,因此其余的是可选的(If you use a consistent naming convention for each of the underlying functions, Impala can automatically determine the names based on the first such clause, so the others are optional)。

关于 UAD 的点对点(end-to-end)的例子,参见 User-Defined Functions for Impala.

使用注意:

  • 你可以使用 C++ 或 JAVA 编写 Impala UDF。对于 Impala 来说,C++ UDFs 是新的、推荐的格式,可以利用本地代码提供更高性能。Impala 和 Hive 都兼容基于 JAVA(Java-based) 的 UDFs,最适合重用现存的 Hive UDFs (Impala 可以运行基于 Java 的 Hive UDFs 但不支持 Hive UDAs)
  • UDF 对应一个 .so 或 .jar 文件,存放在 HDFS 中,并由 CREATE FUNCTION 语句分发到每一个 Impala 节点
  • 当 SQL 语句执行时,Impala 根据处理结果集中所有行的需要调用相关的代码。所有的 UDF 被分为是确定的,也就是说,当传入相同的参数值时总是返回相同的结果。当从之前的调用中结果值已知,Impala 可能跳过也可能不跳过 UDF 的某些调用。因此,不要依赖于 UDF 特定的调用次数,也不要基于一些外部因素如当前时间、随机数函数或当 Impala 执行查询过程中值会发生变化的外部数据源而返回不同的结果(Impala calls the underlying code during SQL statement evaluation, as many times as needed to process all the rows from the result set. All UDFs are assumed to be deterministic, that is, to always return the same result when passed the same argument values. Impala might or might not skip some invocations of a UDF if the result value is already known from a previous call. Therefore, do not rely on the UDF being called a specific number of times, and do not return different result values based on some external factor such as the current time, a random number function, or an external data source that could be updated while an Impala query is in progress)
  • UDF 函数中的参数名不重要,重要的是它们的数量、位置和数据类型
  • 你可以通过创建多版本的使用不同参数签名的函数来重载相同的函数名,但基于安全的原因,不允许创建与内部函数重名的 UDF 函数
  • 在 UDF 代码里,函数返回一个 struct。其中 struct 包含两个字段.。第一个字段是 boolean 类型,表示返回值是否为 NULL(当本字段返回 true 时,返回值被解释为 NULL)。第二个字段与函数的返回类型数据类型相同,当函数返回值不为 NULL 时持有返回值
  • In the UDF code, you represent the function arguments as an initial pointer to a UDF context structure, followed by references to zero or more structs, corresponding to each of the arguments. Each struct has the same 2 fields as with the return value, a boolean field representing whether the argument is NULL, and a field of the appropriate type holding any non-NULL argument value.
  • 关于 UDF 的例子代码和编译说明,参考 Impala 提供的例子目录
  • 因为 对于 UDF 函数主体的文件存放在 HDFS中,自动对所有的 Impala 节点可用。你不需要在服务器之间手工复制 UDF 相关文件
  • 因为 Impala 目前不支持 ALTER FUNCTION 语句,假如你需要重命名函数,移动到其他数据库,或者修改它的前面或其他属性,应先对原函数执行 DROP FUNCTION 语句进行删除,然后执行以期望的属性执行 CREATE FUNCTION 语句创建函数
  • 因为每一个 UDF 与特定的数据库相关,因此在执行任何 CREATE FUNCTION 语句之前,应先执行 USE 语句指定数据库,或者使用 db_name.function_name 来指定数据库

假如为了负载均衡的原因,在 impala-shell 会话中连接到了不同的 Impala 节点,可以启用 SYNC_DDL 查询选项以使得每一 DDL 语句在新的或修改的元数据被所有 Impala 节点接受前等待,直到都被接受后才返回。参考 SYNC_DDL 了解详细信息。

语句类型: DDL

兼容性:

Impala 可以运行 Hive 中创建的 UDF,只要它使用 Impala-compatible 数据类型 (没有组合或嵌套列类型)。Hive 可以运行 Impala 中创建的基于 JAVA(Java-based)的 UDF,而不能使用 C++编写的 UDF。

更多信息: 参见 User-Defined Functions for Impala 了解更多 Impala 中 UDF 的背景信息,使用介绍和例子。

CREATE TABLE 语句

创建表并指定它的列的语法如下:

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name[(col_namedata_type[COMMENT 'col_comment'], ...)]
[COMMENT 'table_comment']
[PARTITIONED BY (col_namedata_type[COMMENT 'col_comment'], ...)]
[
[ROW FORMATrow_format] [STORED ASfile_format]
]
[LOCATION 'hdfs_path']
[WITH SERDEPROPERTIES ('key1'='value1', 'key2'='value2', ...)]
[TBLPROPERTIES ('key1'='value1', 'key2'='value2', ...)] data_type
:primitive_typeprimitive_type
: TINYINT
| SMALLINT
| INT
| BIGINT
| BOOLEAN
| FLOAT
| DOUBLE
| STRING
| TIMESTAMP row_format
: DELIMITED [FIELDS TERMINATED BY 'char' [ESCAPED BY 'char']]
[LINES TERMINATED BY 'char'] file_format:
PARQUET | PARQUETFILE | TEXTFILE
| SEQUENCEFILE
| RCFILE

内部表和外部表:

Impala 默认创建 "内部" 表--由 Impala 管理表相关的数据文件,当表删除时同时实际删除数据文件。假如使用了 EXTERNAL 子句,Impala 将创建 "外部" 表--通常由 Impala 外部产生数据文件,并从它们原来的 HDFS 中的位置进行查询,当删除表时 Impala 不处理这些数据文件

分区表:

PARTITIONED BY 子句根据一个或多个指定列的值拆分数据文件。Impala 查询可以使用分区元数据来最小化读取和网络之间传递的数据,特别是连接查询时。更多信息参见 Partitioning.

指定文件格式:

STORED AS 子句标识了相关数据文件的格式。目前 Impala 可以查询超出其可以创建与插入数据的文件格式。对于 Impala 当前不支持的格式,在 Hive 中执行创建或数据载入操作。例如,Impala 可以创建 SequenceFile 表但是无法载入数据。这也是 Impala 处理各种压缩文件的特定格式(There are also Impala-specific procedures for using compression with each kind of file format)。关于与不同数据文件格式协作的详细信息,参见 How Impala Works with Hadoop File Formats

默认(不使用 STORED AS 子句时)的,Impala 中表创建的数据文件是以 Ctrl-A 作为分隔符的文本文件。使用 ROW FORMAT 子句指定使用不同的分隔符生成或从文件提取数据,如 tab 或 |,或指定不同的行结束符,如回车或换行。当指定分隔符和行结束符号时,用 '\t' 表示 tab,'\n' 表示回车, '\r' 表示换行。

ESCAPED BY 子句对通过 INSERT 语句插入到 Impala TEXTFILE 表的数据文件和已有的直接放置到 Impala 表目录中的文件都有效(你可以使用以下方式提取已有文件的数据:使用 CREATE EXTERNAL TABLE ... LOCATION 语句, 使用 LOAD DATA 语句, 或通过 HDFS 操作如 hdfs dfs -put file hdfs_path)。选择一种不会在文件中其他部分使用的字符作为转义字符,当字段值中出现分隔符时放在每个分隔符实例之前(Choose an escape character that is not used anywhere else in the file, and put it in front of each instance of the delimiter character that occurs within a field value)。被引号引起的字段表示 Impala 不需要对包含嵌入的分隔符的进行解析(Surrounding field values with quotation marks does not help Impala to parse fields with embedded delimiter characters);引号标志它是组成整个列值的一部分。如下想用 \ 作为转义符,需要在 impala-shell 中使用 ESCAPED BY '\\' 进行指定。

克隆表:

使用以下语句,创建一个与其他表具有相同的列、备注、以及其他属性的空表。CREATE TABLE ... LIKE 语句包含一组子句集,当前只支持 LOCATION, COMMENT, STORED AS 子句:

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name
LIKE [db_name.]table_name
[COMMENT 'table_comment']
[STORED ASfile_format]
[LOCATION 'hdfs_path']
Impala SQL 语言元素(翻译)  Note: 希望在一个操作中同时克隆表结构和数据,则使用下面介绍的 CREATE TABLE AS SELECT 语句。

当使用 CREATE TABLE ... LIKE 语句克隆现有表的结构时,新表与原表使用相同的文件格式,因此假如你想要使用不同的文件格式时使用 STORED AS 子句指定新的文件格式。

通常 Impala 不能直接创建 HBase 表,但 Impala 可以使用 CREATE TABLE ... LIKE 语句克隆 HBase 表,保留原始表的文件格式和元数据。

使用 CREATE TABLE ... LIKE 语句克隆 Avro 表时可能有一些例外情况。例如无法用此技术克隆一个设置了 Avro schema 但是没有列的 Avro 表。当有疑问时,在 Hive 中测试运行 CREATE TABLE ... LIKE 操作;如果也有问题,那么他通常在 Impala 中也不会正常。

如果原始表是分区表,新表会继承相同的分区键列。因为新表初始化为空表,它没有继承原始表的实际分区。使用插入数据或执行 ALTER TABLE ... ADD PARTITION 语句在新表上创建分区。

因为 CREATE TABLE ... LIKE 只是操作了表的元数据而不是表的物理数据,可以在之后执行 INSERT INTO TABLE 语句从原始表复制一些数据到新表,也可以同时转换为新的文件格式(对于一些文件格式,Impala 可以通过 CREATE TABLE ... LIKE 进行创建,但是不能插入这些文件格式的数据;这时候就必须使用 Hive 加载数据。参考 How Impala Works with Hadoop File Formats 了解详细信息)。

CREATE TABLE AS SELECT:

CREATE TABLE AS SELECT 语法同时完成创建基于原始表所定义的列的新表,从原始表复制数据到新表,而且不需要单独执行 INSERT 语句。这一语句如此流行,都有自己的缩写 "CTAS"。CREATE TABLE AS SELECT 语法如下:

CREATE [EXTERNAL] TABLE [IF NOT EXISTS]db_name.]table_name
[COMMENT 'table_comment']
[STORED ASfile_format]
[LOCATION 'hdfs_path']
AS
select_statement

参考 SELECT Statement 了解关于 CTAS 语句中 SELECT 位置的语法信息。

新创建的表继承了从原始表中选出的列名,也可以通过在查询中指定列别名来修改。列和表的注释都不会从原始表中继承。

下面例子演示了如何克隆原始表所有数据、列和/或行的部分子集,重排列的顺序,重命名列,用表达式构建新列等:

-- 创建新表并复制所有数据
CREATE TABLE clone_of_t1 AS SELECT * FROM t1;
-- 与 CREATE TABLE LIKE 功能相同
CREATE TABLE empty_clone_of_t1 AS SELECT * FROM t1 WHERE 1=0;
-- 复制部分数据
CREATE TABLE subset_of_t1 AS SELECT * FROM t1 WHERE x > 100 AND y LIKE 'A%';
CREATE TABLE summary_of_t1 AS SELECT c1, sum(c2) AS total, avg(c2) AS average FROM t1 GROUP BY c2;
-- 修改文件格式
CREATE TABLE parquet_version_of_t1 AS SELECT * FROM t1 STORED AS PARQUET;
-- 创建与原始表不同列顺序、列名和数据类型的表
CREATE TABLE some_columns_from_t1 AS SELECT c1, c3, c5 FROM t1;
CREATE TABLE reordered_columns_from_t1 AS SELECT c4, c3, c1, c2 FROM t1;
CREATE TABLE synthesized_columns AS SELECT upper(c1) AS all_caps, c2+c3 AS total, "California" AS state FROM t1;

作为 CTAS 操作的一部分,你可以采用任意 Impala 可写的数据文件格式(当前支持 TEXTFILE 和 PARQUET).。但不能设置文本文件表的底层属性(lower-level properties)如分隔符。尽管可以使用分区表作为源表并从中复制数据,但是不能设置新表的分区子句。

Visibility and Metadata:

你可以通过 TBLPROPERTIES 子句关联任意对象到表的元数据。这会产生一组逗号分隔的键值对并保存到 metastore 数据库中。创建之后可以使用 ALTER TABLE 语句来修改这些属性。当前 Impala 查询不使用表属性字段里的这些数据。一些与其他 Hadoop 组件的交互需要设置 TBLPROPERTIES 字段为特定的值,例如创建 Avro 表或 HBase 表(通常在 Hive 中创建这些特定类型的表,因为这些表需要一些当前 Impala 不支持的额外子句)。

你也可以通过 WITH SERDEPROPERTIES 子句指定键值对来关联表的 SerDes 属性。Impala 有自己的内置的所支持文件的序列化和反序列化器,因此不使用这个属性。为了与 Hive 兼容,一些文件格式的转换需要特定的属性值。

执行 DESCRIBE table_name 语句查看表的列定义和列备注,例如在执行  CREATE TABLE ... LIKE 或 CREATE TABLE ... AS SELECT 语句之前。使用 DESCRIBE FORMATTED table_name 语句来查看更详细的信息,如数据文件的位置和如 ROW FORMAT 和 STORED AS 等子句的值。要查看整体表的注释(而不是单独列的注释)也需要使用 DESCRIBE FORMATTED 语句。

当创建了表之后,当前 impala-shell 会话与其他连接到相同节点的 impala-shell 会话可以立刻看到这个表。当连接到其他节点,通过 Impala 守护进程查询这个表之前,应先执行 INVALIDATE METADATA 语句。

Hive considerations:

Impala 查询会使用表和列的元数据,如表的行数或列的不同值个数。在 Impala 1.2.2 之前,当创建完表和载入相应的数据后,需要在 Hive 中执行 ANALYZE TABLE 语句来收集这些元数据信息。在 Impala 1.2.2 及以上版本,Impala 中 COMPUTE STATS 语句可以生成这些统计信息,不再需要在 Hive 中运行。

Impala SQL 语言元素(翻译)  Note:

Impala 的 CREATE TABLE 语句不能创建 HBase 表,因为当前不支持 HBase 表所需的 STORED BY 子句。可以在 Hive 中创建表,在 Impala 中查询。关于 Impala 使用 HBase 表的信息,参考 Using Impala to Query HBase Tables

CREATE VIEW 语句

CREATE VIEW 语句为复杂的查询创建一个简写。所基于的查询可以执行连接、表达式、重排序列、列别名和其他的 SQL 功能,可以是一个难于理解和维护的查询。

因为视图是个纯粹的逻辑结构(查询的别名)没有对应实体的数据,所以 ALTER VIEW 只会修改  metastore 数据库中的元数据,而不会涉及 HDFS 中的任意数据文件。

CREATE VIEW view_name[(column_list)]
AS select_statement

CREATE VIEW 语句可用以一下场景:

  • 将最长最复杂的 SQL 查询转换为一行查询,你可以在应用中、脚本中、或 impala-shell 交互式查询中执行针对视图的简单的查询。例如:
    select * from view_name;
    select * from view_name order by c1 desc limit 10;

    原始查询越复杂越难以阅读,使用视图的简单查询越有效果。

  • 隐藏底层表和列,当这些发生变化时减少维护量。这时候,只需要用新的名称重建视图,所有查询视图而不是底层表的语句就可以不需要修改就正常运行
  • 测试优化技术并把优化后的查询提供给所有应用使用(To experiment with optimization techniques and make the optimized queries available to all applications)。例如.你发现了一个 WHERE 条件,连接顺序,连接提示(join hints),等等组合中在一起能获得最佳性能的一类查询,你可以建立一个使用这一最佳组合技术的视图。应用可以对视图进行相对简单的查询,而不是重复着一遍又一遍的繁杂而优化的逻辑。如何之后发现了比原始查询更好的优化方式,重建这个视图,所有应用可以立刻从中受益
  • 简化整类的相关查询,特别是在多个表执行连接,对列进行复杂计算、以及其他语法导致整个查询难以理解和调试查询。例如你可以创建一个视图,连接几个表,使用几个 WHERE 条件过滤数据,并从结果集选择几列。应用可以在这个视图上上执行仅仅是 LIMIT, ORDER BY 等类似简单子句上不同的查询。

对于需要一遍遍重复的查询的复杂子句,例如在查询项, ORDER BY, GROUP BY 子句,你可以使用 WITH 子句作为创建视图的替代方案(you can use the WITH clause as an alternative to creating a view)。

假如为了负载均衡的原因,在 impala-shell 会话中连接到了不同的 Impala 节点,可以启用 SYNC_DDL 查询选项以使得每一 DDL 语句在新的或修改的元数据被所有 Impala 节点接受前等待,直到都被接受后才返回。参考 SYNC_DDL 了解详细信息。

例子:

create view v1 as select * from t1;
create view v2 as select c1, c3, c7 from t1;
create view v3 as select c1, cast(c3 as string) c3, concat(c4,c5) c5, trim(c6) c6, "Constant" c8 from t1;
create view v4 as select t1.c1, t2.c2 from t1 join t2 on (t1.id=t2.id);
create view some_db.v5 as select * from some_other_db.t1;

Statement type: DDL

DESCRIBE 语句

DESCRIBE 语句显示表的元数据,例如列的名称和数据类型。语法为:

DESCRIBE [FORMATTED] table

也可以使用简写 DESC。

DESCRIBE FORMATTED 显示更多信息,显示格式与 Apache Hive 类似。扩展信息包括底层详细信息如表是内部表还是外部表,何时创建,文件格式,HDFS 中数据文件位置,对象是表还是视图,以及(对视图来说)从视图定义中获得的查询语句。

Impala SQL 语言元素(翻译)  Note: Compressed 字段表是否包含压缩数据的可靠标志。通常总是 No,因为仅当会话载入数据的时候使用压缩设置,并不会持久保存到表的元数据中。

Usage notes:

当 impalad 守护进程重启后,对某个表的第一次查询可能会比之后的查询时间长,因为该查询执行时会把表的元数据载入到内存中。这种对每个表的一次性(one-time)的延迟可能会误导基准测试的结果或造成不必要的担忧。可以为每一个要查询的表执行 DESCRIBE 语句,为 Impala 的元数据缓存"热身"("warm up")。

当处理保存在 HDFS 中的数据文件时,有时候了解诸如 Impala 表对应的数据文件的路径、namenode 的主机名此类的信息很重要。你可以通过 DESCRIBE FORMATTED 的输出获取这些信息。在诸如 LOAD DATA 和 CREATE TABLE / ALTER TABLE 中的 LOCATION 子句需要指定 HDFS URIs 或路径。在 Linux 命令如 hadoop 和 hdfs 对 HDFS 中的数据文件执行复制,重命名等操作时,也需要知道 HDFS URIs 或路径。

假如为了负载均衡的原因,在 impala-shell 会话中连接到了不同的 Impala 节点,可以启用 SYNC_DDL 查询选项以使得每一 DDL 语句在新的或修改的元数据被所有 Impala 节点接受前等待,直到都被接受后才返回。参考 SYNC_DDL 了解详细信息。

每个表都包括对应的表统计信息和列统计信息。使用 SHOW TABLE STATS table_name 和 SHOW COLUMN STATS table_name 语句来查看这些分类的信息。参见 SHOW Statement 了解详细信息。

Impala SQL 语言元素(翻译)  Important: 对于性能关键( performance-critical)查询中用到的表,插入或替换数据之后,应执行 COMPUTE STATS 语句以确保所有统计信息是最新的。 在 Impala 中执行了 INSERT, LOAD DATA,  CREATE TABLE AS SELECT 语句之后,或者在 Hive 中加载数据并在 Impala 中执行 REFRESH table_name之后, 应考虑更新表的统计信息。对于包含大量数据的表、用于连接查询的表,这一技术特别重要。

例子:

下面的例子演示了对不同模式对象使用标准 DESCRIBE 和 DESCRIBE FORMATTED 的结果:

  • DESCRIBE 表或视图会返回每一个列的名称、类型和备注。对于视图,假如列值是表达式计算得来的,列名会自动根据列的序号生成如 _c0, _c1等等
  • 在创建时没有特别指定格式或存储子句的表被认为是 MANAGED_TABLE (Impala 术语是 "内部表")。它的存放在 HDFS 目录中的数据文件位于 Hive 数据目录下。默认使用文本数据格式
  • 在 DESCRIBE FORMATTED 输出中,视图被视为 VIRTUAL_VIEW。因为继承自基本表,视图的一些属性为 NULL 或空白。定义视图的查询语句是 DESCRIBE FORMATTED 输出的一部分
  • 在 CREATE TABLE 语句中包含额外子句的表在 DESCRIBE FORMATTED 的输出会有差异。表 T2 的输出包括 EXTERNAL_TABLE 关键字,因为使用了 CREATE EXTERNAL TABLE 语法,并且不同的 InputFormat 和 OutputFormat 字段值以对应 Parquet 文件格式
[localhost:21000] > create table t1 (x int, y int, s string);
Query: create table t1 (x int, y int, s string)
[localhost:21000] > describe t1;
Query: describe t1
Query finished, fetching results ...
+------+--------+---------+
| name | type | comment |
+------+--------+---------+
| x | int | |
| y | int | |
| s | string | |
+------+--------+---------+
Returned 3 row(s) in 0.13s
[localhost:21000] > describe formatted t1;
Query: describe formatted t1
Query finished, fetching results ...
+------------------------------+--------------------------------------------------------------------+----------------------+
| name | type | comment |
+------------------------------+--------------------------------------------------------------------+----------------------+
| # col_name | data_type | comment |
| | NULL | NULL |
| x | int | None |
| y | int | None |
| s | string | None |
| | NULL | NULL |
| # Detailed Table Information | NULL | NULL |
| Database: | describe_formatted | NULL |
| Owner: | cloudera | NULL |
| CreateTime: | Mon Jul 22 17:03:16 EDT 2013 | NULL |
| LastAccessTime: | UNKNOWN | NULL |
| Protect Mode: | None | NULL |
| Retention: | 0 | NULL |
| Location: | hdfs://127.0.0.1:8020/user/hive/warehouse/describe_formatted.db/t1 | NULL |
| Table Type: | MANAGED_TABLE | NULL |
| Table Parameters: | NULL | NULL |
| | transient_lastDdlTime | 1374526996 |
| | NULL | NULL |
| # Storage Information | NULL | NULL |
| SerDe Library: | org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe | NULL |
| InputFormat: | org.apache.hadoop.mapred.TextInputFormat | NULL |
| OutputFormat: | org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat | NULL |
| Compressed: | No | NULL |
| Num Buckets: | 0 | NULL |
| Bucket Columns: | [] | NULL |
| Sort Columns: | [] | NULL |
+------------------------------+--------------------------------------------------------------------+----------------------+
Returned 26 row(s) in 0.03s
[localhost:21000] > create view v1 as select x, upper(s) from t1;
Query: create view v1 as select x, upper(s) from t1
[localhost:21000] > describe v1;
Query: describe v1
Query finished, fetching results ...
+------+--------+---------+
| name | type | comment |
+------+--------+---------+
| x | int | |
| _c1 | string | |
+------+--------+---------+
Returned 2 row(s) in 0.10s
[localhost:21000] > describe formatted v1;
Query: describe formatted v1
Query finished, fetching results ...
+------------------------------+------------------------------+----------------------+
| name | type | comment |
+------------------------------+------------------------------+----------------------+
| # col_name | data_type | comment |
| | NULL | NULL |
| x | int | None |
| _c1 | string | None |
| | NULL | NULL |
| # Detailed Table Information | NULL | NULL |
| Database: | describe_formatted | NULL |
| Owner: | cloudera | NULL |
| CreateTime: | Mon Jul 22 16:56:38 EDT 2013 | NULL |
| LastAccessTime: | UNKNOWN | NULL |
| Protect Mode: | None | NULL |
| Retention: | 0 | NULL |
| Table Type: | VIRTUAL_VIEW | NULL |
| Table Parameters: | NULL | NULL |
| | transient_lastDdlTime | 1374526598 |
| | NULL | NULL |
| # Storage Information | NULL | NULL |
| SerDe Library: | null | NULL |
| InputFormat: | null | NULL |
| OutputFormat: | null | NULL |
| Compressed: | No | NULL |
| Num Buckets: | 0 | NULL |
| Bucket Columns: | [] | NULL |
| Sort Columns: | [] | NULL |
| | NULL | NULL |
| # View Information | NULL | NULL |
| View Original Text: | SELECT x, upper(s) FROM t1 | NULL |
| View Expanded Text: | SELECT x, upper(s) FROM t1 | NULL |
+------------------------------+------------------------------+----------------------+
Returned 28 row(s) in 0.03s
[localhost:21000] > create external table t2 (x int, y int, s string) stored as parquet location '/user/cloudera/sample_data';
[localhost:21000] > describe formatted t2;
Query: describe formatted t2
Query finished, fetching results ...
+------------------------------+----------------------------------------------------+----------------------+
| name | type | comment |
+------------------------------+----------------------------------------------------+----------------------+
| # col_name | data_type | comment |
| | NULL | NULL |
| x | int | None |
| y | int | None |
| s | string | None |
| | NULL | NULL |
| # Detailed Table Information | NULL | NULL |
| Database: | describe_formatted | NULL |
| Owner: | cloudera | NULL |
| CreateTime: | Mon Jul 22 17:01:47 EDT 2013 | NULL |
| LastAccessTime: | UNKNOWN | NULL |
| Protect Mode: | None | NULL |
| Retention: | 0 | NULL |
| Location: | hdfs://127.0.0.1:8020/user/cloudera/sample_data | NULL |
| Table Type: | EXTERNAL_TABLE | NULL |
| Table Parameters: | NULL | NULL |
| | EXTERNAL | TRUE |
| | transient_lastDdlTime | 1374526907 |
| | NULL | NULL |
| # Storage Information | NULL | NULL |
| SerDe Library: | org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe | NULL |
| InputFormat: | com.cloudera.impala.hive.serde.ParquetInputFormat | NULL |
| OutputFormat: | com.cloudera.impala.hive.serde.ParquetOutputFormat | NULL |
| Compressed: | No | NULL |
| Num Buckets: | 0 | NULL |
| Bucket Columns: | [] | NULL |
| Sort Columns: | [] | NULL |
+------------------------------+----------------------------------------------------+----------------------+
Returned 27 row(s) in 0.17s

Statement type: DDL

DISTINCT 操作符

SELECT 语句中的 DISTINCT 操作符用于过滤结果结果集中的重复值:

-- 返回一个列的唯一值列表
-- 如何有值为 NULL 的行,则 NULL 也作为返回值之一显示
select distinct c_birth_country from customer;
-- 返回多个列值的唯一组合
select distinct c_salutation, c_last_name from customer;

可以组合使用 DISTINCT 和聚合函数,通常是 COUNT(),来查找一个列有多少不同的值:

-- 统计列的唯一值个数
-- 在 count 时 NULL 值不计入唯一值中
select count(distinct c_birth_country) from customer;
-- 计算唯一值组合的个数
select count(distinct c_salutation, c_last_name) from customer;

Impala SQL 不支持的一个结构是在同一个查询中使用多个聚合函数时使用 DISTINCT 。例如,你无法在一个查询列表中中同时计算 COUNT(DISTINCT c_first_name) 和 COUNT(DISTINCT c_last_name)

Impala SQL 语言元素(翻译)  Note:

在一些数据库系统中总会返回排序后的 DISTINCT 值,Impala 不会对 DISTINCT 值进行排序。假如你需要按字母或数字排序值,必须使用 ORDER BY 子句

DOUBLE 数据类型

8字节(双精度)浮点数据类型,用于 CREATE TABLE 和 ALTER TABLE 语句。

Range: 4.94065645841246544e-324d .. 1.79769313486231570e+308, 正或负

Conversions: Impala 不支持 DOUBLE 到其他数据类型的自动转换。可以使用 CAST() 转换 DOUBLE 值为 FLOAT, TINYINT, SMALLINT, INT, BIGINT, STRING, TIMESTAMP, BOOLEAN。可以使用指数表示法表示 DOUBLE,也可以从字符串转换为 DOUBLE 时使用,例如,1.0e6 表示1百万。

数据类型 REAL 是 DOUBLE 的别名

Related information: Mathematical Functions

DROP DATABASE 语句

从系统中删除数据库,同时删除 HDFS 中对应的 *.db 目录。为了避免丢失数据,删除数据库之前数据库必须为空。

删除数据库的语法是:

DROP (DATABASE|SCHEMA) [IF EXISTS] database_name;

在删除数据库之前,先使用 DROP TABLE, DROP VIEW, ALTER TABLE, ALTER VIEW 语句,删除所有的表和视图,或者把它们移动到其他数据库。

例子:

参见 CREATE DATABASE Statement 中包含 CREATE DATABASE, USE, DROP DATABASE 语句的例子

DROP FUNCTION 语句

移除用户定义函数(UDF),然后在 Impala SELECT 或 INSERT 操作者该函数不再可用

语法:

DROP [AGGREGATE] FUNCTION [IF EXISTS] [db_name.]function_name

Statement type: DML (但受 SYNC_DDL 查询选项影响)

DROP TABLE 语句

删除表语法为:

DROP TABLE [IF EXISTS] [db_name.]table_name

默认 Impala 会同时删除该表对应的 HDFS 目录和数据文件。假如执行了 DROP TABLE 语句而数据问题没有删除,可能是以下原因:

  • 表是外部表(EXTERNAL), Impala 不改变所有文件和目录。当数据是其他 Hadoop 组件控制, Impala 只是从这些原始位置进行数据查询时,应使用外部表
  • 如果对 impala 用户 HDFS 回收站不可用,Impala 也会离开而不删除数据文件(Impala might leave the data files behind unintentionally, if there is no HDFS location available to hold the HDFS trashcan for the impala user)。参见 User Account Requirements 了解如何配置所需的 HDFS 主目录。

请使用 USE 语句选择数据库或使用完整的标识名 db_name.table_name,以确保删除正确的数据库下的表。

使用可选的 IF EXISTS 子句之后,无论表是否存在语句都会执行成功。如果表存在,将对其进行删除操作;如果表不存在,语句则不起作用。这一能力对于删除现有模式对象并创建新对象的标准化安装脚本有意义。通过组合使用包含 IF EXISTS 的 DROP 语句包含 IF NOT EXISTS 子句的 CREATE 语句,脚本可以第一次时(当对象还不存在时) 和之后都允许成功(当其中一些对象已经存在时)。

假如想对数据库执行 DROP DATABASE 语句,首先应当对数据库中的所有表执行 DROP TABLE 语句删除这些表。

例子:

create database temporary;
use temporary;
create table unimportant (x int);
create table trivial (s string);
-- 删除当前数据库中的表
drop table unimportant;
-- 切换到其它数据库
use default;
-- 删除 default 数据库中的表
drop table trivial; ERROR: AnalysisException: Table does not exist: default.trivial -- ...use a fully qualified name.
drop table temporary.trivial;

Statement type: DML (但仍受 SYNC_DDL 查询选项影响)

DROP VIEW 语句

移除原来由 CREATE VIEW 语句创建的指定的视图。因为视图是纯逻辑结构 (是查询的别名)没有对应的数据,DROP VIEW 只会修改 metastore 数据库中的元数据,不会影响 HDFS 中的数据文件。

DROP VIEW [database_name.]view_name

Statement type: DML (但仍受 SYNC_DDL 查询选项影响)

EXPLAIN 语句

返回语句的执行计划,显示 Impala 将用来读取数据,在集群节点中划分工作,在网络间传输中间数据和最终结果的底层机制。在 EXPLAIN 语句后面跟着完整的 SQL 语句,例如:

[impalad-host:21000] > explain select count(*) from customer_address;
PLAN FRAGMENT 0
PARTITION: UNPARTITIONED 3:AGGREGATE
| output: SUM(<slot 0>)
| group by:
| tuple ids: 1
|
2:EXCHANGE
tuple ids: 1 PLAN FRAGMENT 1
PARTITION: RANDOM STREAM DATA SINK
EXCHANGE ID: 2
UNPARTITIONED 1:AGGREGATE
| output: COUNT(*)
| group by:
| tuple ids: 1
|
0:SCAN HDFS
table=default.customer_address #partitions=1 size=5.25MB
tuple ids: 0

你可以查看输出结果以判断查询是否高效执行,如果没有则调整语句和/或模式(You can interpret the output to judge whether the query is performing efficiently, and adjust the query and/or the schema if not)。例如,你可以修改 WHERE 子句,添加提示以更有效地执行连接操作,引入子查询,修改表连接的顺序,添加或修改表的分区,在 Hive 中收集列和/或表的统计信息,或其他的性能调整步骤以进行测试(For example, you might change the tests in the WHERE clause, add hints to make join operations more efficient, introduce subqueries, change the order of tables in a join, add or change partitioning for a table, collect column statistics and/or table statistics in Hive, or any other performance tuning steps)。

如果你是传统数据库背景对数据仓库不熟悉,请记住 Impala 是针对非常大的表的全表扫描进行的优化。数据结构和分布通常不适于通常的 OLTP 环境下的各种索引和单行查找(The structure and distribution of this data is typically not suitable for the kind of indexing and single-row lookups that are common in OLTP environments)。见到扫描整个大表的查询是很寻常的,并不一定是低效查询的标识(Seeing a query scan entirely through a large table is quite common, not necessarily an indication of an inefficient query)。当然,你可以减少扫描数据的数量级,例如通过使用只对分区表特定分区查找的查询,可以提高速度的几个数量级,yibiantazaijimiaozhyunx. Of course, if you can reduce the volume of scanned data by orders of magnitude, for example by using a query that affects only certain partitions within a partitioned table, then you might speed up a query so that it executes in seconds rather than minutes or hours.

更多信息和例子,以帮助你理解 EXPLAIN 输出,请参考 Understanding the EXPLAIN Plan

扩展 EXPLAIN 输出:

为了性能调整和容量规划(例如在 CDH 5 使用资源管理功能),你可以启用 EXPLAIN 语句更详细的信息输出。在 impala-shell 中执行 SET EXPLAIN_LEVEL=verbose 命令。要恢复到原来简洁的 EXPLAIN 输出,执行 SET EXPLAIN_LEVEL=normal 命令(你也可以使用 1 或 0 作为参数传递个 SET 命令以启用或禁用扩展输出)

当启用扩展 EXPLAIN 输出后,EXPLAIN 语句打印关于预估的内存需求,  虚拟核心的最小数量(minimum number of virtual cores), 以及其他可用于微调资源管理的选项,参见 impalad Startup Options for Resource Management 中的描述。(当你设置了 MEM_LIMIT 选项估计了内存数量,预估的内存需求应当略有偏高的,留有犯错的余地,以避免不必要的取消查询)。

扩展 EXPLAIN 输出也报告查询中调用的表的表和列的统计信息是否可用。参见 Table Statistics 和 Column Statistics 了解不同种类的统计信息帮助 Impala 优化查询的细节。

[localhost:21000] > set explain_level=verbose;
EXPLAIN_LEVEL set to verbose
[localhost:21000] > explain select x from t1;
Query: explain select x from t1
+----------------------------------------------------------+
| Explain String |
+----------------------------------------------------------+
| Estimated Per-Host Requirements: Memory=64.00MB VCores=1 |
| |
| PLAN FRAGMENT 0 |
| PARTITION: UNPARTITIONED |
| |
| 1:EXCHANGE |
| cardinality: unavailable |
| per-host memory: unavailable |
| tuple ids: 0 |
| |
| PLAN FRAGMENT 1 |
| PARTITION: RANDOM |
| |
| STREAM DATA SINK |
| EXCHANGE ID: 1 |
| UNPARTITIONED |
| |
| 0:SCAN HDFS |
| table=default.t1 #partitions=1/1 size=18B |
| table stats: unavailable |
| column stats: unavailable |
| cardinality: unavailable |
| per-host memory: 64.00MB |
| tuple ids: 0 |
+----------------------------------------------------------+
Returned 24 row(s) in 0.01s

切换到 Hive shell 收集表和列的统计信息:

hive> analyze table t1 compute statistics;
hive> analyze table t1 compute statistics for columns x;

返回 impala-shell 确认统计信息被 Impala 查询认可。应先执行 REFRESH table 语句,以便载入新的元数据。

[localhost:21000] > set explain_level=verbose;
EXPLAIN_LEVEL set to verbose
[localhost:21000] > refresh t1;
[localhost:21000] > explain select x from t1;
+----------------------------------------------------------+
| Explain String |
+----------------------------------------------------------+
| Estimated Per-Host Requirements: Memory=64.00MB VCores=1 |
| |
| PLAN FRAGMENT 0 |
| PARTITION: UNPARTITIONED |
| |
| 1:EXCHANGE |
| cardinality: unavailable |
| per-host memory: unavailable |
| tuple ids: 0 |
| |
| PLAN FRAGMENT 1 |
| PARTITION: RANDOM |
| |
| STREAM DATA SINK |
| EXCHANGE ID: 1 |
| UNPARTITIONED |
| |
| 0:SCAN HDFS |
| table=default.t1 #partitions=1/1 size=18B |
| table stats: 0 rows total |
| column stats: all |
| cardinality: unavailable |
| per-host memory: 64.00MB |
| tuple ids: 0 |
+----------------------------------------------------------+
Returned 24 row(s) in 0.02s

External Tables

CREATE EXTERNAL TABLE 语句设置 Impala 表指向一个现存的可能在正常的 Impala 数据文件目录以外的 HDFS 位置的数据文件。当你已经在已知的 HDFS 位置有数据文件,这一操作完成以期望的文件格式导入数据到新表里面(This operation saves the expense of importing the data into a new table when you already have the data files in a known location in HDFS, in the desired file format)。

  • 可以在 Impala 查询表中的数据
  • 如果使用 HDFS 操作添加或替换数据,在 impala-shell 里执行 REFRESH 命令以便 Impala 了解数据文件、块位置等等的变化
  • 当在 Impala 中执行 DROP TABLE 语句时,Impala 会删除关于这个文件的连接,但不会实际删除对应的数据,你可以继续在其他 Hadoop 组件和 HDFS 操作中使用这一数据文件

FLOAT 数据类型

4字节(单精度)浮点数据类型,用于 CREATE TABLE 和 ALTER TABLE 语句。

Range: 1.40129846432481707e-45 .. 3.40282346638528860e+38, 正或负

Conversions: Impala 自动转换 FLOAT 为更大精度的 DOUBLE , but not the other way around. 可以使用 CAST() 转换 FLOAT 值为 FLOAT, TINYINT, SMALLINT, INT, BIGINT, STRING, TIMESTAMP, BOOLEAN。可以使用指数表示法表示 FLOAT,也可以从字符串转换为 FLOAT 时使用,例如,1.0e6 表示1百万。

Related information: Mathematical Functions

GROUP BY 子句

在使用类似 COUNT()SUM()AVG()MIN()MAX() 等聚合函数的查询中使用 GROUP BY 子句。在 GROUP BY 子句中列出所有不参与聚合操作的列。

例如, 下面的查询查找总销售量最高的前 5 个项目(使用 SUM() 函数计算销售量,并统计销售交易的数量(使用 COUNT() 函数)。因为项目对应的 ID 列不用于聚合函数,在 GROUP BY 子句指定此列:

select ss_item_sk as Item, count(ss_item_sk) as Times_Purchased, sum(ss_quantity) as Total_Quantity_Purchased
from store_sales group by ss_item_sk order by sum(ss_quantity) desc
limit 5;
+-------+-----------------+--------------------------+
| item | times_purchased | total_quantity_purchased |
+-------+-----------------+--------------------------+
| 9325 | 372 | 19072 |
| 4279 | 357 | 18501 |
| 7507 | 371 | 18475 |
| 5953 | 369 | 18451 |
| 16753 | 375 | 18446 |
+-------+-----------------+--------------------------+

使用 HAVING 子句用于过滤聚合函数的结果,因为不能在 WHERE 子句中使用那些表达式的值。比如,查找 5 个 100 以上销售交易的最低销售量物品可以使用以下查询:

select ss_item_sk as Item, count(ss_item_sk) as Times_Purchased, sum(ss_quantity) as Total_Quantity_Purchased
from store_sales group by ss_item_sk having times_purchased >= 100 order by sum(ss_quantity)
limit 5;
+-------+-----------------+--------------------------+
| item | times_purchased | total_quantity_purchased |
+-------+-----------------+--------------------------+
| 13943 | 105 | 4087 |
| 2992 | 101 | 4176 |
| 4773 | 107 | 4204 |
| 14350 | 103 | 4260 |
| 11956 | 102 | 4275 |
+-------+-----------------+--------------------------+

当执行涉及到科学或财务数据计算时,记住 FLOAT 或 DOUBLE 作为真正的、不能精确表示每一个分数值的浮点数存储(When performing calculations involving scientific or financial data, remember that columns with type FLOAT or DOUBLE are stored as true floating-point numbers, which cannot precisely represent every possible fractional value)。因此,如何你的 GROUP BY 子句包含 FLOAT 或 DOUBLE 列,查询结果可能不会精确匹配查询中的字面值或原始文本件(the results might not precisely match literal values in your query or from an original Text data file)。使用舍入操作、BETWEEN 操作符、或其他运算技术以匹配最“接近”你期望浮点数的字面值。例如,在 ss_wholesale_cost 列上的查询返回的成本值接近但不完全等于被输入的原始分数值。

select ss_wholesale_cost, avg(ss_quantity * ss_sales_price) as avg_revenue_per_sale
from sales
group by ss_wholesale_cost
order by avg_revenue_per_sale desc
limit 5;
+-------------------+----------------------+
| ss_wholesale_cost | avg_revenue_per_sale |
+-------------------+----------------------+
| 96.94000244140625 | 4454.351539300434 |
| 95.93000030517578 | 4423.119941283189 |
| 98.37999725341797 | 4332.516490316291 |
| 97.97000122070312 | 4330.480601655014 |
| 98.52999877929688 | 4291.316953108634 |
+-------------------+----------------------+

Notice how wholesale cost values originally entered as decimal fractions such as 96.94 and 98.38 are slightly larger or smaller in the result set, due to precision limitations in the hardware floating-point types. The imprecise representation of FLOAT and DOUBLE values is why financial data processing systems often store currency using data types that are less space-efficient but avoid these types of rounding errors.

HAVING 子句

通过检测聚合函数的结果而不是检测表中的每一行来对 SELECT 查询的结果进行过滤(Performs a filter operation on a SELECT query, by examining the results of aggregation functions rather than testing each individual table row)。因此总是与聚合函数如 COUNT()SUM()AVG()MIN(),  MAX() 联合使用,通常包含 GROUP BY 子句。

Hints

Impala SQL 方言支持查询提示,用于微调查询内部运作。因为缺少统计信息或其他因素导致效率低下的昂贵查询,使用提示作为临时的解决办法(Specify hints as a temporary workaround for expensive queries, where missing statistics or other factors cause inefficient performance)。所谓提示是指由方括号[]扩起的词(The hints are represented as keywords surrounded by [] square brackets)。

目前所有的提示都是用于控制连接查询的执行策略的(all the hints control the execution strategy for join queries)。在查询的 JOIN 关键词之后立刻紧跟以下结构之一:

  • [SHUFFLE] - 连接操作使用了"分割(partitioned)"技术,使用哈希算法分割两个表对应的行,发送这些行的子集到其他节点进行处理(关键字 SHUFFLE 用于表示 "分割连接(partitioned join)",因为这种连接与"分区表"无关)。 因为当表和索引统计信息不可用时,默认使用另外的"广播(broadcast)"连接机制,你可以在广播连接不适用的情况使用此提示;通常分割连接对具有相似大小的大表之间的连接更有效
  • [BROADCAST] - 使用"广播(broadcast)"技术,把右边(right-hand)表的完整内容发送到所有节点执行连接处理。这是表和索引统计信息不可用时的默认操作方式,所以你通常只需要在元数据失效导致 Impala 错误的选择分割连接操作时才使用此提示。通常当其中一个表比另外一个表小很多的时候更有效(把较小的表放在 JOIN 操作符的右侧)

核对某一查询的 EXPLAIN 的输出信息,确定该程序所采用的连接机制。

Impala SQL 语言元素(翻译)  Note:

因为提示会阻止查询利用新的元数据或改进的查询计划,因此仅当需要解决性能问题时使用,并随时准备在不需要的时候删除,比如 Impala 发布新版本或修复 bug后。

例如下面的查询连接一个大的客户表(customer)和一个小的少于 100 行的表(lookup 表)。右侧的表可以高效的广播到所有执行连接的节点。因此,你可以使用 [broadcast] 提示强制采用关闭连接机制:

select customer.address, state_lookup.state_name
from customer join [broadcast] state_lookup
on (customer.state_id = state_lookup.state_id);

下面的查询连接两个位置大小的大表。你可能需要分别使用两种查询提示,确定哪种更有效的传递每个表的一部分到所有其他节点进行处理。因此,你可能使用 [shuffle] 提示强制使用分割连接机制:

select weather.wind_velocity, geospatial.altitude
from weather join [shuffle] geospatial
on (weather.lat = geospatial.lat and weather.long = geospatial.long);

对于执行三个以上表的连接,提示对它所在的 JOIN 两侧的表有效。连接操作从左到有进行处理。例如,下面的查询使用分割连接表 t1 和 t2,然后使用广播连接他们的连接结果和表 t3 :

select t1.name, t2.id, t3.price
from t1 join [shuffle] t2 join [broadcast] t3
on (t1.id = t2.id and t2.id = t3.id);

关于更多背景信息和性能跳转的注意事项,参见 Joins

当向分区表插入数据,特别是使用 Parquet 文件格式的分区表,你可以在 INSERT 语句中使用提示来减少同时写入 HDFS 的文件数量,以及保存不同分区数据的 1GB 内存缓存的数量。在表名之后紧跟 [SHUFFLE] 或 [NOSHUFFLE] 关键字。当试图在所有节点上构建所有分区的结构数据而导致 INSERT 语句失败或效率低下时,使用 [SHUFFLE] 提示(Put the hint keyword [SHUFFLE] or [NOSHUFFLE] immediately after the table name. Use [SHUFFLE] in cases where an INSERTstatement fails or runs inefficiently due to all nodes attempting to construct data for all partitions.)。此提示在 Impala 1.2.2 及以上版本可用

INSERT 语句

Impala 支持插入数据到表和分区中,这些表和分区既可以是使用 Impala CREATE TABLE 语句创建,也可以是通过 Hive 预先定义的表和分区。

Impala 目前支持:

  • INSERT INTO 语句向表中追加数据
  • INSERT OVERWRITE 语句替换表中数据
  • 使用 SELECT 查询从其他表复制数据。在 Impala 1.2.1 及以上版本,你可以单独使用 CREATE TABLE AS SELECT 语法作为 CREATE TABLE 和 INSERT 语句的替代,它隐藏了实际的 INSERT 关键词。
  • 可以在 INSERT 之前使用可选的 WITH 子句,预先定义 SELECT 部分中使用的子查询
  • 通过 VALUES 子句使用常数表达式来创建一行或多行新行(Create one or more new rows using constant expressions through VALUES clause) (Impala 1.0.1 中添加的 VALUES 子句)
  • 设置被插入列与 INSERT 语句中查询的表的列不同的名称或顺序(Specify the names or order of columns to be inserted, different than the columns of the table being queried by the INSERT statement)(Impala 1.1 中添加)
  • 在 INSERT 关键字后紧跟一个可选的提示子句,用以微调插入到分区表时的行为。提示关键词是 [SHUFFLE] 和 [NOSHUFFLE],包括其中的方括号。默认是 [SHUFFLE]。此提示主要用于插入到 Parquet 分区表时。这是一个耗费资源的操作,因为可能会同时向 HDFS 写入许多文件,并为每一个分区分配单独的 1G 内存缓存(This can be a resource-intensive operation because it potentially involves many files being written to HDFS simultaneously, and separate 1GB memory buffers being allocated to buffer the data for each partition)
Impala SQL 语言元素(翻译)  Note:
  • 插入命令会导致 Hive 元数据的改变(Insert commands that partition or add files result in changes to Hive metadata)。因为 Impala 使用 Hive 元数据,这些变化需要刷新 Hive 元数据。更多信息参见 REFRESH 功能。
  • 目前 Impala 只支持插入数据到 TEXT 文件和 Parquet 文件格式的表。其他格式的表,使用 Hive 插入数据后再使用 Impala 查询

Usage notes:

当向一个较小的数据列如 INT, SMALLINT, TINYINT, FLOAT 插入表达式的值,特别是调用内置函数时,可能需要使用 CAST() 进行转换成对应的类型。Impala 对于较大的类型不会自动转换成较小的类型。比如插入余弦值到一个 FLOAT 列,应在 INSERT 语句中使用明确的转换 CAST(COS(angle) AS FLOAT) 。

假如为了负载均衡的原因,在 impala-shell 会话中连接到了不同的 Impala 节点,可以启用 SYNC_DDL 查询选项以使得每一 DDL 语句在新的或修改的元数据被所有 Impala 节点接受前等待,直到都被接受后才返回。参考 SYNC_DDL 了解详细信息。

Impala SQL 语言元素(翻译)  Important:  对于性能关键(  performance-critical)查询中用到的表,插入或替换数据之后,应执行  COMPUTE STATS 语句以确保所有统计信息是最新的。 在 Impala 中执行了 INSERT, LOAD DATA,  CREATE TABLE AS SELECT 语句之后,或者在 Hive 中加载数据并在 Impala 中执行 REFRESH table_name之后,  应考虑更新表的统计信息。对于包含大量数据的表、用于连接查询的表,这一技术特别重要 。

Statement type: DML (但仍受 SYNC_DDL 查询选项影响)

例子:

下面的例子创建了一个与 Tutorial 中 TAB1 表相同定义而使用了不同的文件格式的新表,并演示如何插入数据到使用 STORED AS TEXTFILE 和 STORED AS PARQUET 子句创建的表中:

CREATE DATABASE IF NOT EXISTS file_formats;
USE file_formats; DROP TABLE IF EXISTS text_table;
CREATE TABLE text_table
( id INT, col_1 BOOLEAN, col_2 DOUBLE, col_3 TIMESTAMP )
STORED AS TEXTFILE; DROP TABLE IF EXISTS parquet_table;
CREATE TABLE parquet_table
( id INT, col_1 BOOLEAN, col_2 DOUBLE, col_3 TIMESTAMP )
STORED AS PARQUET;

使用 INSERT INTO TABLE 语法,每一组新插入的行都会追加到表现有数据之后。这是你如何记录少量的持续到达数据,或提取显存数据之外的新一批数据的方法(This is how you would record small amounts of data that arrive continuously, or ingest new batches of data alongside the existing data)。例如,在执行了 2 次插入 5 行记录的插入语句之后,表中包含 10 行记录:

[localhost:21000] > insert into table text_table select * from default.tab1;
Inserted 5 rows in 0.41s [localhost:21000] > insert into table text_table select * from default.tab1;
Inserted 5 rows in 0.46s [localhost:21000] > select count(*) from text_table;
+----------+
| count(*) |
+----------+
| 10 |
+----------+
Returned 1 row(s) in 0.26s

使用 INSERT OVERWRITE TABLE 语法,每一组新插入的行替换掉表中原有的数据。这是你在数据仓库场景,分析特定日期、季度等的数据同时丢弃之前的数据用于加载数据的查询语句(This is how you load data to query in a data warehousing scenario where you analyze just the data for a particular day, quarter, and so on, discarding the previous data each time)。你可能在一个原始表中保存整个数据集,传输和转换特定的行到一个对于深入分析更紧凑更有效子集中(You might keep the entire set of data in one raw table, and transfer and transform certain rows into a more compact and efficient form to perform intensive analysis on that subset)

例如,下面显示使用 INSERT INTO 子句插入了 5 行数据,然后使用 INSERT OVERWRITE 子句替换为 3 行数据。这样,表中只包含最终的 INSERT 语句插入的 3 行数据。

[localhost:21000] > insert into table parquet_table select * from default.tab1;
Inserted 5 rows in 0.35s [localhost:21000] > insert overwrite table parquet_table select * from default.tab1 limit 3;
Inserted 3 rows in 0.43s
[localhost:21000] > select count(*) from parquet_table;
+----------+
| count(*) |
+----------+
| 3 |
+----------+
Returned 1 row(s) in 0.43s

使用 VALUES 子句允许你通过指定所有列的常量值向表中插入一行或多行。表达式的数量、类型和顺序必须与表的定义匹配。

Impala SQL 语言元素(翻译)  Note: INSERT ... VALUES 技术不适合载入大量的数据到基于 HDFS (HDFS-based)的表,因为插入操作无法并行,并且每一个语句产生单独的数据文件。用于建立小尺寸的表(small dimension tables)或少量数据用于测试 SQL 语法或 HBase 表。不要用于大的 ETL作业或载入操作的基准测试。不要运行包含每次只插入单行数据的 数以千计的 INSERT ... VALUES 语句的脚本。假如在 ETL 操作中会产生很多小文件,那么运行一个在一个 VALUES 子句中包含尽可能多行数据的 INSERT .. VALUES 操作载入数据到一个临时表,作为整个 ETL 管道的一部分,并使用单独的数据方便清理 (If you do run INSERT ... VALUES operations to load data into a staging table as one stage in an ETL pipeline, include multiple row values if possible within each VALUES clause, and use a separate database to make cleanup easier if the operation does produce many tiny files)

下面演示了如何插入一行或多行数据,其中使用不同类型的表达式,字符值,表达式和函数返回值:

create table val_test_1 (c1 int, c2 float, c3 string, c4 boolean, c5 timestamp);
insert into val_test_1 values (100, 99.9/10, 'abc', true, now());
create table val_test_2 (id int, token string);
insert overwrite val_test_2 values (1, 'a'), (2, 'b'), (-1,'xyzzy');

下面演示了 "not implemented" 错误,当你试图向当前 Impala 不支持写入的数据格式的表插入数据时会发生:

DROP TABLE IF EXISTS sequence_table;
CREATE TABLE sequence_table
( id INT, col_1 BOOLEAN, col_2 DOUBLE, col_3 TIMESTAMP )
STORED AS SEQUENCEFILE; DROP TABLE IF EXISTS rc_table;
CREATE TABLE rc_table
( id INT, col_1 BOOLEAN, col_2 DOUBLE, col_3 TIMESTAMP )
STORED AS RCFILE; [localhost:21000] > insert into table rc_table select * from default.tab1;
Remote error
Backend 0:RC_FILE not implemented. [localhost:21000] > insert into table sequence_table select * from default.tab1;
Remote error
Backend 0:SEQUENCE_FILE not implemented.

根据分区列的不同,插入分区表的语法有略微的不同:

create table t1 (i int) partitioned by (x int, y string);
-- 从其他表查询出 INT 类型的列
-- 插入的所有行都具有相同的、在插入语句中指定的 x , y 值
insert into t1 partition(x=10, y='a') select c1 from some_other_table;
-- 从其他表查询出两个 INT 列
-- 插入的所有行具有相同的、在插入语句中指定的 y 值
-- 存入 t1.x 的值是 some_other_table.c2
-- 没有指定值的分区列会使用 SELECT 列表中最后的列来填充(插入分区列的顺序与 SELECT 中的列的顺序相同)
insert into t1 partition(x, y='b') select c1, c2 from some_other_table;
-- 从其他表查询出 INT 和 STRING 列
-- 插入的所有行具有相同的、在插入语句中指定的 x 值
-- 存入 t1.y 的值是 some_other_table.c3
insert into t1 partition(x=20, y) select c1, c3 from some_other_table;
下面例子演示了从一个表复制所有列到另一个表,复制部分列,或在查询列表中指定与表中列不同的顺序:
-- 从 2 各项他的表开始
create table t1 (c1 int, c2 int);
create table t2 like t1;

-- 如果在目标表名之后没有 () 部分,则所有列都必须指定,可以用 * 或列名
insert into t2 select * from t1;
insert into t2 select c1, c2 from t1;
-- 使用了目标表后面的 () 标识,你可以省略列(目标表中这些列的值设为 NULL)
-- 且/或重新排序从原始表查询的列。这就是"列置换(column permutation)"功能
insert into t2 (c1) select c1 from t1;
insert into t2 (c2, c1) select c1, c2 from t1; -- 源表与目标表的列名可以完全不同
-- 你可以从源表复制任意列而不只是对应的列
-- 但是查询出来的列的数量与类型必须与 () 部分中列的数据与类型一致
alter table t2 replace columns (x int, y int);
insert into t2 (y) select c1 from t1; -- 对于分区表,所有的分区列都必须在 () 或 PARTITION 子句中列出;
-- 分区列不能默认为空
create table pt1 (x int, y int) partitioned by (z int);
-- 新表中的列 x 使用 c1 的值
-- 都放入相同的、基于常数值 z 的分区
-- 新表中 y 的值我 NULL
insert into pt1 (x) partition (z=5) select c1 from t1;
-- 我们同样省略了 y 值,因此它们都是 NULL.
-- 插入的 x 值可能在不同的分区,根据分区列 z 的不同而不同
insert into pt1 (x,z) select x, z from t2;
 

并发性考虑: 每一个 INSERT 操作都创建一个唯一名称的新数据文件,因此可以并行执行多个 INSERT INTO 语句而不会有文件名冲突。当数据被插入到 Impala 表后,数据被逐级临时存放到数据目录下的子目录中(the data is staged temporarily in a subdirectory inside the data directory);在此期间,你无法在 Hive 中执行该表的查询。如果插入失败,临时数据文件和子目录被抛弃在数据目录中(If an INSERT operation fails, the temporary data file and the subdirectory could be left behind in the data directory)。这时候,通过执行 hdfs dfs -rm -r 命令,手工删除对应的自目录和数据文件,记得指定子目录名的以 _dir 结尾的完整路径。

INT 数据类型

4字节整数类型,用于 CREATE TABLE 和 ALTER TABLE 语句。

Range: -2147483648 .. 2147483647. There is no UNSIGNED subtype.

Conversions: Impala自动转换为更大的整数类型 (BIGINT) 或浮点数类型 (FLOAT , DOUBLE) 。转换为 TINYINT, SMALLINT,STRING 或 TIMESTAMP 需要使用 CAST() 函数。转换整数值 N 为 TIMESTAMP 时,是根据 Unix 纪元(January 1, 1970)开始的 N 秒来转换。

数据类型 INTEGER 是 INT 的别名

Related information: TINYINT Data TypeBIGINT Data TypeSMALLINT Data TypeTINYINT Data TypeMathematical Functions

内部表

CREATE TABLE 语句默认生成的表是内部表(internal table)。(与之对应的是外部表,由 CREATE EXTERNAL TABLE 语句生成)

  • Impala 在 HDFS 中创建一个目录存放数据文件
  • 通过在 impala-shell 执行 INSERT 语句或在 Hive 中运行 LOAD DATA 语句来载入数据
  • 当执行 DROP TABLE 语句时,Impala 物理删除该目录下的数据文件

INVALIDATE METADATA 语句

标记一个或所有的表的元数据为陈旧的。当通过 Hive shell 创建了表之后,在 Impala 中查询可以访问这个表之前需要执行此语句。当前 Impala 节点执行针对元数据无效的表的查询之前,在下一次对这个表的查询之前,Impala 会重新载入对应的元数据(The next time the current Impala node performs a query against a table whose metadata is invalidated, Impala reloads the associated metadata before the query proceeds)。与通过 REFRESH 语句进行增量元数据的更新比较,这是一个相对昂贵的操作,因此对于现存表中添加数据文件的场景,通常执行 REFRESH 操作而不是 INVALIDATE METADATA 操作(This is a relatively expensive operation compared to the incremental metadata update done by the REFRESH statement, so in the common scenario of adding new data files to an existing table, prefer REFRESH rather than INVALIDATE METADATA)。假如你不熟悉 Impala 使用元数据的方式以及如何与 Hive 共享相同的 metastore 数据库的,参见 Overview of Impala Metadata and the Metastore 了解背景信息。

为了准确的相应查询,Impala 必须拥有关于客户端直接查询的数据库和表的当前的元数据。因此,假如其他实体修改了由 Impala 和 Hive 共享的被 Impala 使用的 metastore 的信息,Impala 缓存的相关信息必须进行更新。然而,这并不意味着 Impala 需要更新所有的元数据。

Impala SQL 语言元素(翻译)  Note:

在 Impala 1.2 及以上版本,一个专门的守护进程(catalogd)负责广播 Impala 产生的 DDL 变更到所有的 Impala 节点。之前,当你连接到一个 Impala 节点创建了一个数据库或表之后,在其他节点*问新的数据库或表之前需要先执行 INVALIDATE METADATA 语句。现在,最新创建或修改的对象被所有节点自动获得。在 Hive 中创建或修改对象之后,仍然必须使用 INVALIDATE METADATA 技术。参见 The Impala Catalog Service 了解目录服务的详细信息。

INVALIDATE METADATA 语句是 Impala 1.1 开始引入,接替了 Impala 1.0 中 REFRESH 语句的一些功能。因为 REFRESH 需要一个表名参数,想要一次刷新所有表的元数据,需要使用 INVALIDATE METADATA 语句。

因为 REFRESH table_name 只对当前 Impala 节点已经认可的表有效,当你在 Hive 中创建了一个新表,你必须使用不带参数的 INVALIDATE METADATA 然后才能在 impala-shell 中看到这个表。当表被 Impala 认可之后,在表上添加数据文件之后可以使用 REFRESH table_name 语句。

INVALIDATE METADATA 和 REFRESH 是相似的(counterparts): INVALIDATE METADATA 等待并在后续查询需要时重载所需的元数据,但是重载表的所有元数据是一个昂贵的操作,特别是对于具有许多分区的大表。REFRESH 立即重载元数据,但是只载入新增加的数据文件的块位置数据,使之成为一个不太昂贵的操作。如果数据以一些更复杂的方式修改,例如 HDFS 平衡器(balancer) 重组,使用 INVALIDATE METADATA 来通过减少本地读取来避免性能损失。如何使用 Impala 1.0,INVALIDATE METADATA 语句与 1.0 版本的 REFRESH 语句的执行相同的操作,而在 Impala 1.1 中 REFRESH 针对常见的为已有表添加新数据文件的情况进行了优化,因此当前需要表名参数。

INVALIDATE METADATA 命令的语法是:

INVALIDATE METADATA [table_name]

默认会刷新缓存的所有表的元数据。如果指定了表名,只刷新这个表的元数据。即使只针对一个表,INVALIDATE METADATA 也比 REFRESH 昂贵,因此对于已有表添加数据文件的情况,应执行 REFRESH 操作。

发生以下情况时需要更新 impalad 实例的元数据:

  • 发生了元数据变化
  • 并且 是集群中其他 impalad 实例或 Hive 导致的变化
  • 并且 是 Impala shell 或 ODBC 客户端直接连接的数据库产生的变化( and the change is made to a database to which clients such as the Impala shell or ODBC directly connect)

当你在执行了 ALTER TABLE,INSERT 或其他的表修改语句的相同的 Impala 节点执行查询时  需要更新元数据。

数据库和表的元数据通常由下列语句修改:

  • Hive - 通过 ALTER, CREATE, DROP , INSERT 操作
  • Impalad - 通过 CREATE TABLE, ALTER TABLE, INSERT 操作

INVALIDATE METADATA 导致表的元数据被标记为过期的,并在表被下一次引用之前重载。对于巨大的表,这一过程可能需要相当的时间;因此你可能更愿意用 REFRESH 执行加载来避免不可预知的延迟,例如下一次对表的引用是在执行基准测试时。

下面的例子演示了在 Hive 中创建了新表后你可能使用 INVALIDATE METADATA 语句的情况(例如 SequenceFile 或 HBase 表)。执行 INVALIDATE METADATA 语句之前,如果试图访问这些表,Impala 会返回 "table not found" 错误。 DESCRIBE 语句会导致这些表最新的元数据立即载入,避免了下次这些表查询时的延迟。

[impalad-host:21000] > invalidate metadata;
[impalad-host:21000] > describe t1;
...
[impalad-host:21000] > describe t2;
...

关于 Impala 和 Hive 组合操作中更多使用 REFRESH 和 INVALIDATE METADATA 的例子,参见 Switching Back and Forth Between Impala and Hive

假如你需要在启动 impala-shell 会话之后确保元数据是最新的,使用带有 -r 或 --refresh_after_connect 命令行选项的 impala-shell 。因为这一操作对每一个表的下一查询增加了延迟,对于有许多分区的大表潜在的昂贵,尽量避免在生产环境的每日操作中使用该选项(Because this operation adds a delay to the next query against each table, potentially expensive for large tables with many partitions, try to avoid using this option for day-to-day operations in a production environment)

Joins

连接操作是一个组合两个或多个表中的数据,并返回包含了一些或所有表中的项目的结果集操作(A join query is one that combines data from two or more tables, and returns a result set containing items from some or all of those tables)。通常以下情况使用连接查询:

  • 当相关的数据从不同的源获得,每一个数据集物理存放在单独的表里。例如,你可能从业务记录中有地址数据,与电话列表或户籍数据进行交叉校验(When related data arrives from different sources, with each data set physically residing in a separate table. For example, you might have address data from business records that you cross-check against phone listings or census data)
    Impala SQL 语言元素(翻译)  Note: Impala 可以连接不同文件格式的表,包括 Impala 管理表和 HBase 表。例如,你可能在 Hbase 表中保持小的维度表,以便单行查找和更新,使用 Parquet 或其他针对扫描操作优化的二进制文件格式保存大的事实表。这样,你可以执行一个交叉引用维表和事实表的 连接查询。
  • 在数据标准化中,一项技术减少数据冗余的技术就是拆分到多个表里(When data is normalized, a technique for reducing data duplication by dividing it across multiple tables)。这种组织常见于传到关系数据库系统的数据,例如,不是在每个表中都重复存放一个长字符串,比如客户名,而是每一个表中都包含一个数字的客户ID。需要显示客户名称的查询可以"连接"表指定客户ID对应的名称
  • 当某些列很少需要查询时,可以把它移动到单独的表中以减少常用查询的开销。例如对雇员数据的查询很少会需要 biography 字段。把它放到单独的表里会减少常用的查找雇员地址和电话时的 I/O 数量。需要 biography 列的查询可以通过连接它所在的单独的表来实现。
Impala SQL 语言元素(翻译)  Note:

连接查询的性能是 Impala 的重要方面,因为复杂的连接查询是资源密集操作。一个有效的连接查询比低效的连接查询产生低得多的网络传输和 CPU 负载。为了最佳结果:

  • 确保查询中涉及到的所有的表的表和列的统计信息可用,特别是任意连接条件中涉及的列。使用 SHOW TABLE STATS table_name 和 SHOW COLUMN STATS table_name 检查
  • 如果表和列的统计信息不可用,先连接最大的表。你可以通过 SHOW TABLE STATS table_name 和 SHOW COLUMN STATS table_name 语句检查统计信息是否存在。在 Impala 1.2.2 及以上版本,使用 COMPUTE STATS 语句在表和列一级采集统计信息,在任何实质性的插入和载入数据操作之后保证统计信息最新
  • 如果表和列的统计信息不可用,基于总体大小和 WHERE 子句,选择最有选择性过滤前的表作为随后连接的表。连接具有最有选择性过滤器的表返回最少数量的行(If table or column statistics are not available, join subsequent tables according to which table has the most selective filter, based on overall size and WHERE clauses. Joining the table with the most selective filter results in the fewest number of rows being returned)

关于连接查询性能的更多信息和例子,参见 Performance Considerations for Join Queries

连接查询的结果集被包括在 ON/USING 子句中使用的对应的连接列名或 WHERE 子句中所有表的使用相等比较的列过滤(The result set from a join query is filtered by including the corresponding join column names in an ON or USING clause, or by using equality comparisons for columns from both tables in the WHERE clause)

[localhost:21000] > select c_last_name, ca_city from customer join customer_address where c_customer_sk = ca_address_sk;
+-------------+-----------------+
| c_last_name | ca_city |
+-------------+-----------------+
| Lewis | Fairfield |
| Moses | Fairview |
| Hamilton | Pleasant Valley |
| White | Oak Ridge |
| Moran | Glendale |
...
| Richards | Lakewood |
| Day | Lebanon |
| Painter | Oak Hill |
| Bentley | Greenfield |
| Jones | Stringtown |
+-------------+------------------+
Returned 50000 row(s) in 9.82s

连接查询一个潜在的缺点就是很差的查询结构导致的过量资源使用。例如,如果 T1 包含 1000 行而表 T2 包含 1,000,000 行,查询 SELECT columns FROM t1 JOIN t2 会返回多达 10亿行(1000 * 1,000,000)。为了最大化减少大数据集上的失控的查询出现的机会, Impala 要求每一个连接查询的不同表之间的列必须至少包含一个等值条件。

因为即使包含相等子句,结果集依然可能很大,像我们在之前例子里看到的,你可能需要使用 LIMIT 子句来返回一个结果集的子集:

[localhost:21000] > select c_last_name, ca_city from customer, customer_address where c_customer_sk = ca_address_sk limit 10;
+-------------+-----------------+
| c_last_name | ca_city |
+-------------+-----------------+
| Lewis | Fairfield |
| Moses | Fairview |
| Hamilton | Pleasant Valley |
| White | Oak Ridge |
| Moran | Glendale |
| Sharp | Lakeview |
| Wiles | Farmington |
| Shipman | Union |
| Gilbert | New Hope |
| Brunson | Martinsville |
+-------------+-----------------+
Returned 10 row(s) in 0.63s

或者使用额外的比较操作或聚合函数把一组大的结果集压缩成小的结果集:

[localhost:21000] > -- 查找生活在指定小镇的用户名
[localhost:21000] > select distinct c_last_name from customer, customer_address where
c_customer_sk = ca_address_sk
and ca_city = "Green Acres";
+---------------+
| c_last_name |
+---------------+
| Hensley |
| Pearson |
| Mayer |
| Montgomery |
| Ricks |
...
| Barrett |
| Price |
| Hill |
| Hansen |
| Meeks |
+---------------+
Returned 332 row(s) in 0.97s [localhost:21000] > -- 查看这个小镇上有多少用户名以"A"开头
[localhost:21000] > select count(distinct c_last_name) from customer, customer_address where
c_customer_sk = ca_address_sk
and ca_city = "Green Acres"
and substr(c_last_name,1,1) = "A";
+-----------------------------+
| count(distinct c_last_name) |
+-----------------------------+
| 12 |
+-----------------------------+
Returned 1 row(s) in 1.00s

因为连接查询可能包括从硬盘上读取大量的数据,通过网络发送大量的数据,载入大量的数据到内存中进行比较和过滤,你可能需要做基准测试,性能分析和查询优化,以找出对你的数据集、硬件容量、网络配置和集群负载最优的连接查询。

Impala 支持两类连接 partitioned joins 和 broadcast joins。假如表和列的统计信息不准确,或数据分布的倾斜(some quirk of the data distribution),导致 Impala 对特定的连接选择了错误的机制,考虑使用查询提示作为临时的解决办法。详细信息参见 Hints

查看教程中不同种类连接的例子:

LIKE 运算符

一种字符串(STRING)数据的比较运算符,包含基本的通配符能力,使用 _ 匹配单个字符, % 匹配多个字符。参数表达式必须匹配整个字符串的值。通常把通配符 % 放在字符串结尾效率更高( it is more efficient to put any % wildcard match at the end of the string.)

例子:

select distinct c_last_name from customer where c_last_name like 'Mc%' or c_last_name like 'Mac%';
select count(c_last_name) from customer where c_last_name like 'M%';
select c_email_address from customer where c_email_address like '%.edu'; -- 我们可以通过调用函数找到 4 个字母并且以 'M' 开头的名字...
select distinct c_last_name from customer where length(c_last_name) = 4 and substr(c_last_name,1,1) = 'M';
-- ...或者使用更易读的方式匹配 M 后面跟着 3 个字母
select distinct c_last_name from customer where c_last_name like 'M___';

关于使用正则表达式的更通用的查找操作,参见 REGEXP Operator.

LIMIT 子句

SELECT 查询中的 LIMIT 子句设置结果集中的最大行数。在以下场景有用:

  • 返回一个 top-N 查询的确定的前 N 项,such as the 10 highest-rated items in a shopping category or the 50 hostnames that refer the most traffic to a web site.
  • 演示表或特定查询的一些样本值,其中查询没有使用 ORDER BY 子句
  • 当表大于预期,或 WHERE 子句匹配的行数超出预期而导致海量结果集时,保证查询正常(To keep queries from returning huge result sets by accident if a table is larger than expected, or a WHERE clause matches more rows than expected)

Usage notes:

原先 LIMIT 子句必须使用数字,在 Impala 1.2.1 及以上版本,可以是数字表达式。

Impala 要求任意的包含 ORDER BY 子句的查询同时使用 LIMIT 子句。因为排序海量结果集需要如此多的内存,而对 Impala 来说 top-N 查询如此常见,这一子句的组合防止意外的查询导致协调器节点上的内存消耗过大。你可以指定 LIMIT 子句作为查询的一部分,或者在 impala-shell 里通过命令 SET DEFAULT_ORDER_BY_LIMIT=... 为会话的所有查询设置一个默认限制,或者以 -default_query_options default_order_by_limit=... 选项启动 impalad 以设置实例级别的限制。

参见 ORDER BY Clause 了解详细信息,和为了避免在每一个 ORDER BY 查询中添加明确的 LIMIT 子句可用的查询选项。

在 Impala 1.2.1 及以上版本,你可以结合 LIMIT 子句和 OFFSET 子句,产生一个与 top-N 查询不同的小结果集,例如,返回 11 到 20 的项目。这种技术可以用于模拟 "分页(paged)" 结果集。因为 Impala 查询通常包括大量的 I/O 操作,仅在你不能重写应用逻辑为了兼容性而使用此技术。为了最佳性能和扩展性,无论现实,查询你期望需要的,并缓存到应用端,并使用应用逻辑显示小组的结果集。

例子:

下面的例子演示 LIMIT 子句如何限制结果集,它在其他子句如 WHERE 之后生效(The following example shows how the LIMIT clause caps the size of the result set, with the limit being applied after any other clauses such as WHERE)。

[localhost:21000] > create database limits;
[localhost:21000] > use limits;
[localhost:21000] > create table numbers (x int);
[localhost:21000] > insert into numbers values (1), (3), (4), (5), (2);
Inserted 5 rows in 1.34s
[localhost:21000] > select x from numbers limit 100;
+---+
| x |
+---+
| 1 |
| 3 |
| 4 |
| 5 |
| 2 |
+---+
Returned 5 row(s) in 0.26s
[localhost:21000] > select x from numbers limit 3;
+---+
| x |
+---+
| 1 |
| 3 |
| 4 |
+---+
Returned 3 row(s) in 0.27s
[localhost:21000] > select x from numbers where x > 2 limit 2;
+---+
| x |
+---+
| 3 |
| 4 |
+---+
Returned 2 row(s) in 0.27s

对于 top-N 查询,应同时使用 ORDER BY 和 LIMIT 子句。假如你已经设置了 DEFAULT_ORDER_BY_LIMIT 查询选项,这样你不需要明确的在每个包含 ORDER BY 的查询添加 LIMIT 子句。你也可以同时设置 ABORT_ON_DEFAULT_LIMIT_EXCEEDED 查询选项以避免意外截断结果集。

[localhost:21000] > select x from numbers order by x;
ERROR: NotImplementedException: ORDER BY without LIMIT currently not supported
[localhost:21000] > set default_order_by_limit=1000;
DEFAULT_ORDER_BY_LIMIT set to 1000
[localhost:21000] > select x from numbers order by x;
+---+
| x |
+---+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+---+
Returned 5 row(s) in 0.35s
[localhost:21000] > set abort_on_default_limit_exceeded=true;
ABORT_ON_DEFAULT_LIMIT_EXCEEDED set to true
[localhost:21000] > set default_order_by_limit=3;
DEFAULT_ORDER_BY_LIMIT set to 3
[localhost:21000] > select x from numbers order by x;
ERROR: DEFAULT_ORDER_BY_LIMIT has been exceeded.
Cancelling query ...

LOAD DATA 语句

LOAD DATA 语句简化了 Impala 内部表从 HDFS 位置移动一个或目录下所有数据文件到该表对应的 Impala 数据目录中的 ETL 过程(The LOAD DATA statement streamlines the ETL process for an internal Impala table by moving a data file or all the data files in a directory from an HDFS location into the Impala data directory for that table)。

语法:

LOAD DATA INPATH 'hdfs_file_or_directory_path' [OVERWRITE] INTO TABLE tablename
[PARTITION (partcol1=val1,partcol2=val2...)]

Usage Notes:

  • 加载的数据文件会移动而不是复制到 Impala 数据目录
  • 你可以指定被移动的单个数据文件 HDFS 路径,或要移动的所有文件所在的目录。但是不能使用任何形式的通配符只移动目录中的部分文件。当加载一个目录下的所有数据文件时,请确保所有的数据文件都在顶层目录下,没有在其中的嵌套目录里
  • 目前 Impala LOAD DATA 语句只能从 HDFS 中加载,不能从本地文件系统中加载。不支持 Hive LOAD DATA 语句的 LOCAL 关键字。必须指定路径而不能使用 hdfs:// URI
  • 基于速度方面的考虑,只对有限的错误进行检查(In the interest of speed, only limited error checking is done)。加入加载的文件具有错误的文件格式,与目标表不同的列,或其他的类型不匹配, Impala 不会为 LOAD DATA 语句引发错误。之后查询该表可能产生运行时错误或意外的结果。目前,LOAD DATA 语句检查所做的只是避免未压缩文本文件和 LZO 压缩文本文件在同一个表中混合在一起
  • 当你在 LOAD DATA 参数中指定了 HDFS 目录名,目录下的任何隐藏文件 (以 . 开头的文件名) 都不会移动到 Impala 数据目录中
  • 加载的数据文件在新位置保留原有的名称,除非与现存的数据文件名称冲突,这时候会对新文件名略加修改成为唯一的名称(重名文件的处理与 Hive LOAD 语句略有不同,Hive 中是替换重名的文件(The name-mangling is a slight difference from the Hive LOAD DATA statement, which replaces identically named files))
  • 通过提供一种简单的方法从已知的 HDFS 位置传输文件到 Impala 数据目录结构,LOAD DATA 语句可以让你避免记忆包含 Impala 数据库和表的 HDFS 目录树的位置与布局(使用  DESCRIBE FORMATTED table_name 语句,作为一种快速检查 Impala 表的数据文件位置的方法)
  • 对于提取分区表的新数据使用 PARTITION 子句特别方便。当你收到一个时间段、地理区域、或其他对应着一个或多个分区列的部分数据时,你可以直接加载这些数据到对应的 Impala 数据目录,如果表有多个分区列,那么可能目录下有多层嵌套目录。当表被分区时,你必须为所有的分区列指定常量值(When the table is partitioned, you must specify constant values for all the partitioning columns)

假如为了负载均衡的原因,在 impala-shell 会话中连接到了不同的 Impala 节点,可以启用 SYNC_DDL 查询选项以使得每一 DDL 语句在新的或修改的元数据被所有 Impala 节点接受前等待,直到都被接受后才返回。参考 SYNC_DDL 了解详细信息。

Impala SQL 语言元素(翻译)  Important:  对于性能关键(    performance-critical)查询中用到的表,插入或替换数据之后,应执行   COMPUTE STATS 语句以确保所有统计信息是最新的。 在 Impala 中执行了 INSERT, LOAD DATA,  CREATE TABLE AS SELECT 语句之后,或者在 Hive 中加载数据并在 Impala 中执行 REFRESH table_name之后,    应考虑更新表的统计信息。对于包含大量数据的表、用于连接查询的表,这一技术特别重要   。

例子:

首先,我们使用一个简单的 Python 脚本写入不同数量的字符串(每行一个)到存储在 cloudera HDFS 用户下的文件里(当执行类似的 hdfs dfs 操作时替换为你自己的 HDFS 用户帐号)。

$ random_strings.py 1000 | hdfs dfs -put - /user/cloudera/thousand_strings.txt
$ random_strings.py 100 | hdfs dfs -put - /user/cloudera/hundred_strings.txt
$ random_strings.py 10 | hdfs dfs -put - /user/cloudera/ten_strings.txt

接下来,我们创建一个表并加载一组初始化数据到里面。记住,除非你指定了 STORED AS 子句,Impala 表默认是用 Ctrl-A(\01) 作为字段分隔符的 TEXTFILE 格式。这个例子使用单列的表,因此分隔符无所谓。对于大规模的 ETL 作业,你可能通常使用二进制格式的数据文件,如 Parquet 或 Avro,并使用对应的文件格式把它们加载到Impala 表中。

[localhost:21000] > create table t1 (s string);
[localhost:21000] > load data inpath '/user/cloudera/thousand_strings.txt' into table t1;
Query finished, fetching results ...
+----------------------------------------------------------+
| summary |
+----------------------------------------------------------+
| Loaded 1 file(s). Total files in destination location: 1 |
+----------------------------------------------------------+
Returned 1 row(s) in 0.61s
[kilo2-202-961.cs1cloud.internal:21000] > select count(*) from t1;
Query finished, fetching results ...
+------+
| _c0 |
+------+
| 1000 |
+------+
Returned 1 row(s) in 0.67s
[localhost:21000] > load data inpath '/user/cloudera/thousand_strings.txt' into table t1;
ERROR: AnalysisException: INPATH location '/user/cloudera/thousand_strings.txt' does not exist.

如前面例子最后显示的信息标识的,数据文件已经从它原始的位置被移走。下面的例子展示了数据文件已经被移动到目标表的 Impala 数据目录,并保留原有的文件名:

$ hdfs dfs -ls /user/hive/warehouse/load_data_testing.db/t1
Found 1 items
-rw-r--r-- 1 cloudera cloudera 13926 2013-06-26 15:40 /user/hive/warehouse/load_data_testing.db/t1/thousand_strings.txt

下面的例子演示了 INTO TABLE 和 OVERWRITE TABLE 子句的不同。表中已经有 1000 条记录。当执行了包含 INTO TABLE 子句的 LOAD DATA 语句后,表中增加了 100 行,总共 1100 行。而当执行了包含 OVERWRITE INTO TABLE 子句的 LOAD DATA 语句后,之前的内容没有了,现在表中只包含刚加载的数据文件中的 10 行记录。

[localhost:21000] > load data inpath '/user/cloudera/hundred_strings.txt' into table t1;
Query finished, fetching results ...
+----------------------------------------------------------+
| summary |
+----------------------------------------------------------+
| Loaded 1 file(s). Total files in destination location: 2 |
+----------------------------------------------------------+
Returned 1 row(s) in 0.24s
[localhost:21000] > select count(*) from t1;
Query finished, fetching results ...
+------+
| _c0 |
+------+
| 1100 |
+------+
Returned 1 row(s) in 0.55s
[localhost:21000] > load data inpath '/user/cloudera/ten_strings.txt' overwrite into table t1;
Query finished, fetching results ...
+----------------------------------------------------------+
| summary |
+----------------------------------------------------------+
| Loaded 1 file(s). Total files in destination location: 1 |
+----------------------------------------------------------+
Returned 1 row(s) in 0.26s
[localhost:21000] > select count(*) from t1;
Query finished, fetching results ...
+-----+
| _c0 |
+-----+
| 10 |
+-----+
Returned 1 row(s) in 0.62s

Statement type: DML (但仍受 SYNC_DDL 查询选项影响)

MAX 函数

返回一组数值中最大值的聚合函数。与 MIN 函数相反。它唯一的参数可以是数值列,或者列值上的函数或表达式的数值结果。输入列中 NULL 的行被忽略。假如表为空,或者提供给 MAX 函数的所有值都为 NULL,则返回 NULL。

当查询包含 GROUP BY 子句时,对分组值的每一种组合返回一个值。

Return type: 与输入参数相同类型

Examples:

-- 查找 t1 表中 c1 列的最大值
select max(c1) from t1;
-- 查找 t1 表中 2013 年 1 月的 c1 列的最大值
select max(c1) from t1 where month = 'January' and year = '';
-- 查找 t1 表中 s 列的最大长度
select max(length(s)) from t1;
-- 可与 DISTINCT 和/或 GROUP BY 同时使用
-- 返回多个结果
select month, year, max(purchase_price) from store_stats group by month, year;
-- 在执行计算之前,过滤输入中的重复值
select max(distinct x) from t1;

MIN 函数

返回一组数值中最小值的聚合函数。与 MAX 函数相反。它唯一的参数可以是数值列,或者列值上的函数或表达式的数值结果。输入列中 NULL 的行被忽略。假如表为空,或者提供给 MIN 函数的所有值都为 NULL,则返回 NULL。

当查询包含 GROUP BY 子句时,对分组值的每一种组合返回一个值。

Return type: 与输入参数相同类型

Examples:

-- Find the smallest value for this column in the table.
select min(c1) from t1;
-- Find the smallest value for this column from a subset of the table.
select min(c1) from t1 where month = 'January' and year = '';
-- Find the smallest value from a set of numeric function results.
select min(length(s)) from t1;
-- Can also be used in combination with DISTINCT and/or GROUP BY.
-- Return more than one result.
select month, year, min(purchase_price) from store_stats group by month, year;
-- Filter the input to eliminate duplicates before performing the calculation.
select min(distinct x) from t1;

NDV 函数

返回类似于 COUNT(DISTINCT col) "不同值的数量(number of distinct values)" 结果的近似值的聚合函数。它比 COUNT 和 DISTINCT 组合的速度更快,并使用固定大小的内存,因此对于高基数的列更少的内存消耗(thus is less memory-intensive for columns with high cardinality)

这是内部 COMPUTE STATS 语句计算列的不同值数量所采用的机制。

Usage notes:

因为数量是估计的,它可能不会精确反映列的不同值,特别是基数非常低或非常高时。如何估计值比表中的行数高, Impala 在查询规划期间会内部调整这个值。

Return type: BIGINT

NULL

各种数据库中都有熟悉的 NULL 概念,但是每一种 SQL 方言可能对 NULL 有自己独有的行为和限制。对于大数据处理,NULL 值的精确语义很重要:任何误解都可能导致不正确的结果或错误格式的(misformatted)数据,修正这一数据对于大数据集相当耗时。

  • NULL 与空字符串的值不同。空字符串表现为里面没有字符的字符串,"" 或 ''.
  • 在一个字符分隔文本文件里,NULL 值使用特殊标记 \N 表示
  • 当 Impala 插入数据到分区表,并且其中一个分区列为 NULL 或空字符串时,数据被放置到保存这两种值的特定分区。当这些值在查询中返回时,无论原始值为 NULL 或空字符串,返回值都是  NULL 。这一行为是为了与 Hive 中处理分区表中的 NULL 值的做法兼容。 Hive 不允许空字符串作为分区键,并在查询中返回 NULL 值的时候返回一个字符串值如 __HIVE_DEFAULT_PARTITION__ 而不是 NULL。例如:
    create table t1 (i int) partitioned by (x int, y string);
    -- Select an INT column from another table, with all rows going into a special HDFS subdirectory
    -- named __HIVE_DEFAULT_PARTITION__. Depending on whether one or both of the partitioning keys
    -- are null, this special directory name occurs at different levels of the physical data directory
    -- for the table.
    insert into t1 partition(x=NULL, y=NULL) select c1 from some_other_table;
    insert into t1 partition(x, y=NULL) select c1, c2 from some_other_table;
    insert into t1 partition(x=NULL, y) select c1, c3 from some_other_table;
  • 当定义列的时候,不支持 NOT NULL 子句来限制列中不允许 NULL 值(There is no NOT NULL clause when defining a column to prevent NULL values in that column)
  • 不支持 DEFAULT 子句指定非空列的默认值
  • 如何 INSERT 操作中只提到了一部分列,则没有提到的列在所有插入的行中都为 NULL
  • 在 Impala 1.2.1 及以上版本,所有的 NULL 值会列在 ORDER BY ... ASC 查询结果集的末尾,列在 ORDER BY ... DESC 查询的结果集的开头。事实上, NULL 被认为大于排序中其他的所有值。之前的 Impala 总是把 NULL 值放到最后,即使是 ORDER BY ... DESC 查询。Impala 1.2.1 中的最新行为使得与其他在通用数据库系统更兼容。在 Impala 1.2.1 及以上版本,你可以在 ORDER BY 子句的末尾添加 NULLS FIRST 或 NULLS LAST 子句来覆盖或指定 NULL 的排序行为。

    Impala SQL 语言元素(翻译)  Note: 因为在当前 Hive 查询中 NULLS FIRST 和 NULLS LAST 关键字不可用,你使用这些关键字创建的视图在 Hive 中都不可用
  • 除了 ORDER BY 排序中的比较以外,所有与 NULL 的比较都会返回 NULL,使得比较毫无意义。例如, 10 > NULL 返回 NULL, 10 < NULL 同样返回 NULL, 5 BETWEEN 1 AND NULL 一样返回 NULL

OFFSET 子句

SELECT 查询中的 OFFSET 子句会导致结果集从逻辑上的第一行后某些数值之后的行开始。结果集从 0 开始编号,因此 OFFSET 0 与不使用 OFFSET 子句的查询生成相同的结果集。总是在包含 ORDER BY (以便清楚哪一项目是第一个、第二个、等等) 和 LIMIT (这样结果集涵盖了有限的范围,如第 0-9 行, 100-199 行,等等) 组合的语句中使用此子句

在 Impala 1.2.1 及以上版本,你可以结合 LIMIT 子句和 OFFSET 子句,产生一个与 top-N 查询不同的小结果集,例如,返回 11 到 20 的项目。这种技术可以用于模拟 "分页(paged)" 结果集。因为 Impala 查询通常包括大量的 I/O 操作,仅在你不能重写应用逻辑为了兼容性而使用此技术。为了最佳性能和扩展性,无论现实,查询你期望需要的,并缓存到应用端,并使用应用逻辑显示小组的结果集。

Examples:

下面例子演示了如何运行一个原来为传统数据库应用写的"分页(paging)"查询。因为通常 Impala 查询处理成 M 或 G 的数据,每一次从硬盘读取大量的数据文件,运行一个单独的查询来获取每一组少量的项目是低效的。仅当为了移植旧的应用保持兼容性时使用此技术,然后重写应用代码使用返回大结果集的单个查询,并从缓存数据中显示分页结果集。

[localhost:21000] > create table numbers (x int);
[localhost:21000] > insert into numbers select x from very_long_sequence;
Inserted 1000000 rows in 1.34s
[localhost:21000] > select x from numbers order by x limit 5 offset 0;
+----+
| x |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
Returned 5 row(s) in 0.26s
[localhost:21000] > select x from numbers order by x limit 5 offset 5;
+----+
| x |
+----+
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
+----+
Returned 5 row(s) in 0.23s

ORDER BY 子句

熟悉的 SELECT 查询中的 ORDER BY 子句基于一个或多个列的值排序结果集。对于分布式查询,这是一个相当昂贵的操作,因为整个结果集在执行排序之前必须被处理和传输到一个节点上。相比不使用 ORDER BY 子句,这将需要更多的内存容量。即使使用和不使用 ORDER BY 子句的查询需要大约相同的时间来完成,主观上也会感觉它出现的更慢,因为直到处理完成才有结果可用,而不是一当匹配了 WHERE 子句结果集就逐渐回来。

ORDER BY 子句的完整语法是:

ORDER BYcol1[,col2...] [ASC | DESC] [NULLS FIRST | NULLS LAST]

默认的排序 (与使用 ASC 关键字相同) 把最小的值放在结果集的开始位置,最大值在结束位置。使用 DESC 关键字逆转这一顺序。

参见 NULL 了解 NULL 值在排序的结果集中如何定位,以及如何使用 NULLS FIRST 和 NULLS LAST 子句 (在 Impala 1.2.1 开始的NULL 值在 ORDER BY ... DESC 查询中位置的改变更兼容标准,并且新增了 NULLS FIRST 和 NULLS LAST 关键字)

Impala 要求任意的包含 ORDER BY 子句的查询同时使用 LIMIT 子句。因为排序海量结果集需要如此多的内存,而对 Impala 来说 top-N 查询如此常见,这一子句的组合防止意外的查询导致协调器节点上的内存消耗过大。你可以指定 LIMIT 子句作为查询的一部分,或者在 impala-shell 里通过命令 SET DEFAULT_ORDER_BY_LIMIT=... 为会话的所有查询设置一个默认限制,或者以 -default_query_options default_order_by_limit=... 选项启动 impalad 以设置实例级别的限制。

参见 SELECT Statement 中更多查询中使用 ORDER BY 子句的例子。关于可以用来微调 ORDER BY 子句的行为,避免修改你的 SQL 语句添加明确的 LIMIT 子句的查询选项,参见 DEFAULT_ORDER_BY_LIMIT and ABORT_ON_DEFAULT_LIMIT_EXCEEDED

REFRESH 语句

为了准确的相应查询,作为协调器的 Impala 节点(你通过 impala-shell, JDBC, ODBC 连接的节点) 必须拥有查询中引用的表和数据库当前的元数据。假如你不熟悉 Impala 如何使用元数据以及它与 Hive 共享的相同 metastore 数据库,请参考 Overview of Impala Metadata and the Metastore 了解背景信息。

在以下场景,使用 REFRESH 语句加载特定表最新的 metastore 元数据和 块位置数据(block location data):

  • 当为表加载新的数据文件到 HDFS 数据目录后 (一旦你设置了定期加载数据到 Impala 中的 ETL 管道操作,这通常是最常见的需要刷新元数据的原因)
  • 当在 Hive 中执行了 ALTER TABLE, INSERT, LOAD DATA, 或其他修改表的 SQL 语句之后

你只需要在你连接并执行查询的节点执行 REFRESH 语句。协调器节点在集群中的 Impala 节点之间拆分工作,并发送正确的 HDFS 块的读取请求,不需要依赖其他节点上的元数据。

REFRESH 从 metastore 数据库重新载入表的元数据,并对新添加到表的 HDFS 数据目录中的任意新数据文件的底层块位置执行增量的重载(and does an incremental reload of the low-level block location data to account for any new data files added to the HDFS data directory for the table)。它是低开销、单表的操作,针对 HDFS 中新添加的数据文件这一常用场景做了特别优化。

REFRESH 命令的语法为:

REFRESH table_name

只有指定表的元数据被刷新。该表必须已经存在并且对 Impala 已知,或者是因为是在 Impala 而不是 Hive 中运行的 CREATE TABLE 语句,或者是因为前一个 INVALIDATE METADATA 语句导致 Impala 重载了整个元数据目录。

Impala SQL 语言元素(翻译)  Note:

在 Impala 1.2 及以上版本,Impala 中作为 ALTER TABLE, INSERT 和 LOAD DATA 语句的结果而导致的元数据的任意变化,目录服务广播到所有 Impala 节点。因此仅当你通过 Hive 加载数据或直接在 HDFS 中操作数据文件后,才需要执行 REFRESH 语句。参考 The Impala Catalog Service 了解目录服务的详细信息。

在 Impala 1.2.1 及以上版本,另一种避免各个节点的数据不一致的方法是在执行 DDL 语句、 INSERT 、 LOAD DATA 语句前启用 SYNC_DDL 查询选项。

REFRESH 语句的功能在 Impala 1.1 以后发生了变化。现在需要传递表名参数。使用 INVALIDATE METADATA 命令刷新所有表的元数据。

因为 REFRESH table_name 只能对已经被 Impala 感知的表工作,当你在 Hive 中创建了新表之后,你必须先执行不包含参数的 INVALIDATE METADATA 语句,然后才能在 impala-shell 中看到这个表。当这个表被 Impala 感知之后,就可以在表添加数据文件之后执行 REFRESH table_name 语句。

INVALIDATE METADATA 和 REFRESH 是相似的(counterparts): INVALIDATE METADATA 等待并在后续查询需要时重载所需的元数据,但是重载表的所有元数据是一个昂贵的操作,特别是对于具有许多分区的大表。REFRESH 立即重载元数据,但是只载入新增加的数据文件的块位置数据,使之成为一个不太昂贵的操作。如果数据以一些更复杂的方式修改,例如 HDFS 平衡器(balancer) 重组,使用 INVALIDATE METADATA 来通过减少本地读取来避免性能损失。如何使用 Impala 1.0,INVALIDATE METADATA 语句与 1.0 版本的 REFRESH 语句的执行相同的操作,而在 Impala 1.1 中 REFRESH 针对常见的为已有表添加新数据文件的情况进行了优化,因此当前需要表名参数。

发生以下情况时需要更新 impalad 实例的元数据:

  • 发生了元数据变化
  • 并且 是 Hive 导致的变化
  • 并且 是 Impala shell 或 ODBC 客户端直接连接的数据库产生的变化(the change is made to a database to which clients such as the Impala shell or ODBC directly connect)

当你在 Impala 而不是 Hive 中执行了 ALTER TABLE,INSERT 或其他的表修改语句的时候  需要更新元数据。

数据库和表的元数据通常由以下语句修改:

  • Hive - 通过 ALTER, CREATE, DROP , INSERT 操作
  • Impalad - 通过 CREATE TABLE, ALTER TABLE, INSERT 操作。在 Impala 1.2 及以上版本,这些变化被 Impala 目录服务传播给所有 Impala 节点

使用 REFRESH 子句后表的元数据被立即重载。对巨大的表, 这一过程可能花费大量的时间;但是应当执行刷新操作以避免不可预知的延迟,例如你是在下面的基准测试中引用这个表。

假如为了负载均衡的原因,在 impala-shell 会话中连接到了不同的 Impala 节点,可以启用 SYNC_DDL 查询选项以使得每一 DDL 语句在新的或修改的元数据被所有 Impala 节点接受前等待,直到都被接受后才返回。参考 SYNC_DDL 了解详细信息。

Examples:

下面的例子演示了可能使用 REFRESH 语句的情况,在手工向 Impala 数据目录添加了 HDFS 数据文件之后:

[impalad-host:21000] > refresh t1;
[impalad-host:21000] > refresh t2;
[impalad-host:21000] > select * from t1;
...
[impalad-host:21000] > select * from t2;
...

关于 Impala 和 Hive 组合操作中更多使用 REFRESH 和 INVALIDATE METADATA 的例子,参见 Switching Back and Forth Between Impala and Hive

Statement type: DDL

Related impalad options:

在 Impala 1.0 中,impala-shell 的 -r 选项会执行 REFRESH 操作重载所有表的元数据。

在 Impala 1.1 及以上版本,这一选项执行 INVALIDATE METADATA 语句,因为 REFRESH 当前需要表名参数。因为重载所有表的元数据很昂贵,所以尽量避免在生产环境的每日操作中使用该选项。

在 Impala 1.2 及以上版本,需要 -r 选项的情况更少,因为 Impala 中 SQL 语句导致的元数据修改会自动广播到所有节点。

Impala SQL 语言元素(翻译)  Important:  对于性能关键(  performance-critical)查询中用到的表,插入或替换数据之后,应执行  COMPUTE STATS 语句以确保所有统计信息是最新的。 在 Impala 中执行了 INSERT, LOAD DATA,  CREATE TABLE AS SELECT 语句之后,或者在 Hive 中加载数据并在 Impala 中执行 REFRESH table_name之后,  应考虑更新表的统计信息。对于包含大量数据的表、用于连接查询的表,这一技术特别重要 。

REGEXP 操作符

测试一个值是否匹配正则表达式。使用 POSIX 正则表达式语法,其中 ^ 和 $ 在正则表达式开始和结束(Uses the POSIX regular expression syntax where ^ and $ match the beginning and end of the string), . 对应任意单个字母, * 代表 0 个或多个项目的序列, + 对应出现一次或多次项目的序列, ? 产生一次非贪婪的匹配,如此等等。

正则表达式必须匹配完整的值,而不仅仅是其中的部分内容。假如你只需要匹配出现在中间任意部分的字符,在正则的开始和/或最后使用 .* 。因此,^ 和 $ 通常是多余的,尽管你可能已经在你重用的其他地方的正则表达式中包含它们(although you might already have them in your expression strings that you reuse from elsewhere)

RLIKE 操作符是 REGEXP 的同义词。

竖线 | 是间隔符,通常在括号 () 中使用以匹配不同的序列。括号 () 中的组不允许反向引用(backreferences)。使用 regexp_extract() 内置函数获取括号()中匹配的那部分内容。

Examples:

-- 查找 first name 以 'J' 开头, 之后可以跟 0 或更多个字母
select c_first_name, c_last_name from customer where c_first_name regexp 'J.*'; -- 查找 'Macdonald', 其中第一个 'a' 是可选的, 'D' 可以是大写也可以是小写
-- ^...$ 不是必需的,但使整个表达式看起来很清晰
select c_first_name, c_last_name from customer where c_last_name regexp '^Ma?c[Dd]onald$'; -- 查找 'Macdonald' 或 'Mcdonald'
select c_first_name, c_last_name from customer where c_last_name regexp '(Mac|Mc)donald'; -- 查找 last name 以 'S' 开始, 然后是一个或多个的元音,然后是 'r', 然后是其他任意字符
-- 匹配 'Searcy', 'Sorenson', 'Sauer'.
select c_first_name, c_last_name from customer where c_last_name regexp 'S[aeiou]+r.*'; -- 查找 last name 以 2 个或多个元音结束:是 a,e,i,o,u 之一的字符
select c_first_name, c_last_name from customer where c_last_name regexp '.*[aeiou]{2,}$'; -- 你可以使用 [] 块中字母的范围开头,例如查找 last name 以 A, B, C 开头的
select c_first_name, c_last_name from customer where c_last_name regexp '[A-C].*'; -- 假如你不确定大小写,前导或末尾的空格等等,可以先在列上执行字符串函数进行处理
select c_first_name, c_last_name from customer where lower(c_last_name) regexp 'de.*';

RLIKE 操作符

REGEXP 操作符的同义词

SELECT 语句

Impala SELECT 查询支持:

  • SQL 数据类型: booleantinyintsmallintintbigintfloatdoubletimestampstring.
  • 在 SELECT 关键字之前的一个可选的 WITH 子句,用于定义一个子查询,子查询和其中的的列名可以在之后的主查询中引用
  • 每一个查询的 DISTINCT 子句,参考 DISTINCT Operator 了解详细信息
  • FROM 子句中的子查询
  • WHERE, GROUP BY, HAVING 子句
  • ORDER BY 子句。Impala 要求同时使用 LIMIT 子句
    Impala SQL 语言元素(翻译)  Note:

    ORDER BY 查询需要限制结果集的条数。可以在启动 Impala 时设置这一限制,也可以在 Impala shell 中设置。目前不支持通过 ODBC 和 JDBC 设置查询选项,因此你使用这些连接方式,在启动 Impala 时设置这一限制。例如使用类似下面的命令在 shell 中设置这一值:

    [impalad-host:21000] > set default_order_by_limit=50000

    当启动 Impala 时,对 impalad 守护进程使用包含 -default_query_option 启动参数。例如,使用类似下面的命令启动 impala为 ORDER BY 查询设置限制:

    $ GLOG_v=1 nohup impalad -state_store_host=state_store_hostname-hostname=impalad_hostname-default_query_options default_order_by_limit=50000
  • JOIN 子句。支持 Left, right, semi, full, 和 outer joins。Impala 1.2.2 添加 CROSS JOIN 操作。参见 Joins 了解详细信息。 你可以在 SELECT 关键字之后紧跟 STRAIGHT_JOIN 关键字,用来覆盖 Impala 内部处理 join 子句时表载入的顺序(You can also include the keyword STRAIGHT_JOINimmediately after the SELECT keyword to override the reordering of join clauses that Impala does internally.)
  • UNION ALL
  • LIMIT
  • 外部表
  • 关系操作如大于\小于或等于
  • 算术运算符如加法或减法
  • 逻辑/布尔操作 AND, OR, NOT。Impala 不支持对应的符合 &&, ||, !.
  • 普通的 SQL 内置函数如 COUNT, SUM, CAST, LIKE, IN, BETWEEN, COALESCE。 Impala 支持的内置函数见 Built-in Function Support.
  • 使用 WITH 子句来抽象重复的,如聚合函数,会在相同的查询中多次引用的子句(WITH 子句实际在 SELECT 语句之前执行)

SHOW 语句

SHOW 子句是一种灵活的获取 Impala 中不同种类对象信息的方式。你可以运行 SHOW object_type 语句来查看当前数据库中对应的对象,或运行 SHOW object_type IN database_name 来查看特定数据库中的对象。

执行以下语句,显示特定种类所有可用对象的列表:

  • SHOW DATABASES
  • SHOW SCHEMAS - SHOW DATABASES 的别名
  • SHOW TABLES [IN database_name]
  • SHOW FUNCTIONS [IN database_name]
  • SHOW CREATE TABLE [database_name].table_name
  • SHOW TABLE STATS [database_name.]table_name. 参见 Table Statistics 了解使用注意事项和例子
  • SHOW COLUMN STATS [database_name.]table_name. 参见 Column Statistics 了解使用注意事项和例子

Usage notes:

SHOW DATABASES 语句通常是第一次连接到一个实例后执行的第一个语句。通常执行 SHOW DATABASES 查看可以在 USE db_namestatement 中使用的数据库,当切换数据库之后执行 SHOW TABLES 查看你可以在 SELECT 和 INSERT 语句中使用的名称。

随着时间的推移模式的变化,你可能运行 CREATE TABLE 语句然后跟着几个 ALTER TABLE 语句。为了捕获这些语句累积的效果,SHOW CREATE TABLE 显示了重现当前表结构对应的 CREATE TABLE 语句。你可以在脚本中使用这一输出来设置或克隆一组表,而不是重新执行原始的那一组 CREATE TABLE 和 ALTER TABLE 语句。当创建变化的原始表,或在不同的系统克隆一个原始表时,你可能需要修改 SHOW CREATE TABLE 输出中如数据库名、 LOCATION 字段以及其他在目标系统上不同的部分。

SHOW FUNCTIONS 的输出包括每个函数的参数签名。在使用 DROP FUNCTION 语句时需要指定这一函数的参数签名。你可能会有几个具有相同名称、接受不同类型参数的 UDFs。

当启用授权后,SHOW 语句输出被限制为你具有权限的对象。那里可能有其他的数据库、表或其他的等等,但名字是隐藏的。如果你认为对象存在但是在 SHOW 输出中无法看到,请让系统管理员授予你这些对象所需的权限。参见 Using Authorization with Impala 了解特定种类的对象如何建立授权和权限。

Examples:

下面例子演示了在一个不熟悉的系统中如何定位一个特定的表。初始连接的是 DEFAULT 数据库;一个在所有系统中都存在的数据库。你可以不切换到对应的数据库就执行 SHOW TABLES IN db_name 语句,或切换到特定的数据库后执行 SHOW TABLES 语句。

[localhost:21000] > show databases;
+--------------------+
| name |
+--------------------+
| analyze_testing |
| avro |
| ctas |
| d1 |
| d2 |
| d3 |
| default |
| file_formats |
| hbase |
| load_data |
| partitioning |
| regexp_testing |
| reports |
| temporary |
+--------------------+
Returned 14 row(s) in 0.02s
[localhost:21000] > show tables in file_formats;
+--------------------+
| name |
+--------------------+
| parquet_table |
| rcfile_table |
| sequencefile_table |
| textfile_table |
+--------------------+
Returned 4 row(s) in 0.01s
[localhost:21000] > use file_formats;
[localhost:21000] > show tables;
+--------------------+
| name |
+--------------------+
| parquet_table |
| rcfile_table |
| sequencefile_table |
| textfile_table |
+--------------------+
Returned 4 row(s) in 0.01s

SMALLINT 数据类型

2字节整数类型,用于 CREATE TABLE 和 ALTER TABLE 语句

Range: -32768 .. 32767. 不包括无符号子类型

Conversions: Impala自动转换为更大的整数类型 (INT, BIGINT) 或浮点数类型 (FLOAT , DOUBLE) 。转换为 TINYINT,STRING 或 TIMESTAMP 需要使用 CAST() 函数。转换整数值 N 为 TIMESTAMP 时,是根据 Unix 纪元(January 1, 1970)开始的 N 秒来转换。

Related information: TINYINT Data TypeBIGINT Data TypeTINYINT Data TypeINT Data TypeMathematical Functions

STRING 数据类型

一种用于 CREATE TABLE 和 ALTER TABLE 语句的数据类型。

Length: 32,767 字节(严格地说。最大长度对应 C/C++ 常数 INT_MAX,在 Linux 系统中通常是 32,767)。在定义 STRING 列时不要使用任何长度限制约束,就像你可能在关系数据库系统中熟悉的 VARCHAR, CHAR, 或类似的列类型。

Character sets: 为了所有的 Impala 子系统都支持,限制字符串的值为 ASCII 码集。UTF-8 字符数据可以被 Impala 存储并通过查询获取,但是对于包含非 ASCII(non-ASCII) 字符的 UTF-8 字符串,不保证字符串操作函数、计算操作、或 ORDER BY 子句能正常工作。For any national language aspects such as collation order or interpreting extended ASCII variants such as ISO-8859-1 or ISO-8859-2 encodings, Impala does not include such metadata with the table definition. 假如你需要排序、操作、或显示依赖于这些国家语言特点(national language characteristics)的字符串数据,请在客户端实现此逻辑。

转换:

  • Impala 不会自动把 STRING 转换为任意其他类型

  • 可以使用 CAST() 函数,转换 STRING 为 TINYINT, SMALLINT, INT, BIGINT, FLOAT, DOUBLE, TIMESTAMP

  • 可以直接把 STRING 转换为 BOOLEAN。可以使用 CASE 表达式计算字符串的值如 'T', 'true', 等等,并返回对应的 Boolean 类型的 true 和 false

  • 可以把 BOOLEAN 值转换为 STRING,true 返回 '1',false 返回 '0'

Related information: String FunctionsDate and Time Functions

SUM 函数

返回一组数值的和的聚合函数。它唯一的参数可以是数值列,或者列值上的函数或表达式的数值结果。输入列中 NULL 的行被忽略。假如表为空,或者提供给 SUM 函数的所有值都为 NULL,则返回 NULL。

当查询包含 GROUP BY 子句时,对分组值的每一种组合返回一个值。

Return type: 输入参数是整数,则返回 BIGINT,输入参数是浮点数,则返回 DOUBLE

Examples:

-- Total all the values for this column in the table.
select sum(c1) from t1;
-- Find the total for this column from a subset of the table.
select sum(c1) from t1 where month = 'January' and year = '';
-- Find the total from a set of numeric function results.
select sum(length(s)) from t1;
-- Often used with functions that return predefined values to compute a score.
select sum(case when grade = 'A' then 1.0 when grade = 'B' then 0.75 else 0) as class_honors from test_scores;
-- Can also be used in combination with DISTINCT and/or GROUP BY.
-- Return more than one result.
select month, year, sum(purchase_price) from store_stats group by month, year;
-- Filter the input to eliminate duplicates before performing the calculation.
select sum(distinct x) from t1;

TIMESTAMP 数据类型

用于 CREATE TABLE 和 ALTER TABLE 语句的数据类型,对应一个时间点。

Range: 在内部, TIMESTAMP 值中时间部分的精度是纳秒

Time zones: Impala 不支持保存本地时区的时间戳,为了避免因为意外的时区问题导致的未知的结果。时间戳都是相对 GMT 保存的。

Conversions: Impala 自动转换正确格式的 STRING 字面值为 TIMESTAMP 值。 Timestamp 值接受 YYYY-MM-DD HH:MM:SS.sssssssss 格式,可以只包含日期,或者只包含时间,带或不带第二部分的小数部分。例如,你可以设置 TIMESTAMP 值为 '1966-07-30', '08:30:00', '1985-09-25 17:45:30.005'。也可以转换整数或浮点数 N 为 TIMESTAMP,生成一个自 UNIX 纪元开始的 N 秒值对应的时间戳(January 1, 1970)。

Partitioning:

尽管不能使用 TIMESTAMP 作为分区键,但可以提取单独的年、月、日、小时、等等并基于这些分区。因为分区键列的值在 HDFS 目录名中表示,而不是数据文件中的字段表示,如果需要,可以保留原始的 TIMESTAMP 值,而不是浪费空间的重复数据。参考 Partition Key Columns 了解关于日期和时间值的分区的详细信息。

例子:

select cast('1966-07-30' as timestamp);
select cast('1985-09-25 17:45:30.005' as timestamp);
select cast('08:30:00' as timestamp);
select hour('1970-01-01 15:30:00'); -- Succeeds, returns 15.
select hour('1970-01-01 15:30'); -- Returns NULL because seconds field required.
select hour('1970-01-01 27:30:00'); -- Returns NULL because hour value out of range.
select dayofweek('2004-06-13'); -- Returns 1, representing Sunday.
select dayname('2004-06-13'); -- Returns 'Sunday'.
select date_add('2004-06-13', 365); -- Returns 2005-06-13 with zeros for hh:mm:ss fields.
select day('2004-06-13'); -- Returns 13.
select datediff('1989-12-31','1984-09-01'); -- How many days between these 2 dates?
select now(); -- Returns current date and time in UTC timezone. create table dates_and_times (t timestamp);
insert into dates_and_times values
('1966-07-30'), ('1985-09-25 17:45:30.005'), ('08:30:00'), (now());

Related information: 不同格式日期类型之间的转换、或执行日期计算,使用 Date and Time Functions 中描述的时间日期函数。

TINYINT 数据类型

1字节整数类型,用于 CREATE TABLE 和 ALTER TABLE 语句。

Range: -128 .. 127. 不是无符号子类型

Conversions: Impala自动转换为更大的整数类型 (SMALLINT, INT, BIGINT) 或浮点数类型 (FLOAT , DOUBLE) 。转换为 STRING 或 TIMESTAMP 需要使用 CAST() 函数。转换整数值 N 为 TIMESTAMP 时,是根据 Unix 纪元(January 1, 1970)开始的 N 秒来转换。

Related information: INT Data TypeBIGINT Data TypeSMALLINT Data TypeMathematical Functions

UNION 子句

使用 UNION 子句允许你组合多个查询的结果集。默认的,组合结果集就类似于应用 DISTINCT 操作符。

Syntax:

query_1 UNION [DISTINCT | ALL] query_2

Usage notes:

仅使用 UNION 关键字与使用 UNION DISTINCT 相同。因为对于大的结果集消除重复是内存密集操作,所有尽可能使用 UNION ALL(也就是说,当你知道 union 操作中不同的查询将不产生任何重复,或者重复值可以接受)。

当对 UNION ALL 或 UNION 查询执行 ORDER BY 操作,通常同时需要 LIMIT 子句。假如你设置了 DEFAULT_ORDER_BY_LIMIT 查询选项, 对整个结果集应用 ORDER BY 和 LIMIT 子句,那么把 UNION 查询放到子查询里,SELECT from 子查询,并把 ORDER BY 子句放在子查询的外面的最末尾。

Examples:

首先,我们准备一些例子数据,包括重复的 1 的值。

[localhost:21000] > create table few_ints (x int);
[localhost:21000] > insert into few_ints values (1), (1), (2), (3);
[localhost:21000] > set default_order_by_limit=1000;

本例中演示了返回两个查询的所有结果的 UNION ALL 操作,没有其他的过滤器以消除重复。对于 Impala 通常查询的大结果集,这是最节省内存的技术。

[localhost:21000] > select x from few_ints order by x;
+---+
| x |
+---+
| 1 |
| 1 |
| 2 |
| 3 |
+---+
Returned 4 row(s) in 0.41s
[localhost:21000] > select x from few_ints union all select x from few_ints;
+---+
| x |
+---+
| 1 |
| 1 |
| 2 |
| 3 |
| 1 |
| 1 |
| 2 |
| 3 |
+---+
Returned 8 row(s) in 0.42s
[localhost:21000] > select * from (select x from few_ints union all select x from few_ints) as t1 order by x;
+---+
| x |
+---+
| 1 |
| 1 |
| 1 |
| 1 |
| 2 |
| 2 |
| 3 |
| 3 |
+---+
Returned 8 row(s) in 0.53s
[localhost:21000] > select x from few_ints union all select 10;
+----+
| x |
+----+
| 10 |
| 1 |
| 1 |
| 2 |
| 3 |
+----+
Returned 5 row(s) in 0.38s

本例子演示了不包含 ALL 关键字的 UNION 子句,它压缩了结果集消除了重复值,使得查询花费更多的时间和更多的内存。这一额外的处理使得对于会返回成千上万行的记录的查询这一技术不被推荐。

[localhost:21000] > select x from few_ints union select x+1 from few_ints;
+---+
| x |
+---+
| 3 |
| 4 |
| 1 |
| 2 |
+---+
Returned 4 row(s) in 0.51s
[localhost:21000] > select x from few_ints union select 10;
+----+
| x |
+----+
| 2 |
| 10 |
| 1 |
| 3 |
+----+
Returned 4 row(s) in 0.49s
[localhost:21000] > select * from (select x from few_ints union select x from few_ints) as t1 order by x;
+---+
| x |
+---+
| 1 |
| 2 |
| 3 |
+---+
Returned 3 row(s) in 0.53s

USE 语句

默认的,一开始连接到 Impala 实例的时候,你连入的是 default 数据库。在 impala-shell 会话中执行 USE db_name 语句切换到其它数据库。当你在表名前不使用数据库名前缀,任意的 CREATE TABLE, INSERT, SELECT,或其他语句都在当前数据库运行(The current database is where any CREATE TABLE, INSERT, SELECT, or other statements act when you specify a table without prefixing it with a database name)。

Usage notes:

以下情况下应切换默认数据库:

  • 避免在带数据库名前缀访问引用的表。例如, SELECT * FROM t1 JOIN t2 而不是 SELECT * FROM db.t1 JOIN db.t2.
  • 在同一个数据库中作一系列操作,如创建表、插入数据、并查询表

在启动 impala-shell 时设置 -d db_name 选项,为特定数据库自动执行 USE 语句。这一选项对运行 SQL 脚本有用,例如没有硬编码到 SQL 源码中的针对多个数据库的安装或测试脚本。

Examples:

参见 CREATE DATABASE Statement 中包括 CREATE DATABASE, USE, DROP DATABASE 的例子

VALUES 子句

VALUES 子句是通用的设置单行或多行的所有列的方式。通常在 INSERT 语句中使用 VALUES 子句为添加到表的单行或多行设置所有列值。

Impala SQL 语言元素(翻译)  Note:  INSERT ... VALUES 技术不适合载入大量的数据到基于 HDFS (HDFS-based)的表,因为插入操作无法并行,并且每一个语句产生单独的数据文件。用于建立小尺寸的表(small dimension tables)或少量数据用于测试 SQL 语法或 HBase 表。不要用于大的 ETL作业或载入操作的基准测试。不要运行包含每次只插入单行数据的  数以千计的  INSERT ... VALUES 语句的脚本。假如在 ETL 操作中会产生很多小文件,那么运行一个在一个 VALUES 子句中包含尽可能多行数据的 INSERT .. VALUES 操作载入数据到一个临时表,作为整个 ETL 管道的一部分,并使用单独的数据方便清理 (If you do run INSERT ... VALUES operations to load data into a staging table as one stage in an ETL pipeline, include multiple row values if possible within each VALUES clause, and use a separate database to make cleanup easier if the operation does produce many tiny files)

下面的例子演示了:

  • 如何使用 VALUES 子句插入单行记录
  • 如何使用 VALUES 子句插入多行记录
  • 如何使用 VALUES 子句通过 INSERT INTO 追加单行或多行数据到表中,或者通过 INSERT OVERWRITE 替换现有表的内容
  • VALUES 子句中的条目可以是常量(literals)、函数值、或其他表达式
[localhost:21000] > describe val_example;
Query: describe val_example
Query finished, fetching results ...
+-------+---------+---------+
| name | type | comment |
+-------+---------+---------+
| id | int | |
| col_1 | boolean | |
| col_2 | double | |
+-------+---------+---------+ [localhost:21000] > insert into val_example values (1,true,100.0);
Inserted 1 rows in 0.30s
[localhost:21000] > select * from val_example;
+----+-------+-------+
| id | col_1 | col_2 |
+----+-------+-------+
| 1 | true | 100 |
+----+-------+-------+ [localhost:21000] > insert overwrite val_example values (10,false,pow(2,5)), (50,true,10/3);
Inserted 2 rows in 0.16s
[localhost:21000] > select * from val_example;
+----+-------+-------------------+
| id | col_1 | col_2 |
+----+-------+-------------------+
| 10 | false | 32 |
| 50 | true | 3.333333333333333 |
+----+-------+-------------------+

当在 INSERT 语句中使用时,Impala 中的 VALUES 子句不支持设置表的列的子集或使用不同的顺序。使用 VALUES 子句时应以与表中定义相同的顺序设置所有的列赋值,其中想要忽略的值使用 NULL 赋值。

就像在其他语句中的表一样, 使用括号括起 VALUES 子句并用 AS 子句为整个对象和其中需要引用的列指定别名:

[localhost:21000] > select * from (values(4,5,6),(7,8,9)) as t;
+---+---+---+
| 4 | 5 | 6 |
+---+---+---+
| 4 | 5 | 6 |
| 7 | 8 | 9 |
+---+---+---+
[localhost:21000] > select * from (values(1 as c1, true as c2, 'abc' as c3),(100,false,'xyz')) as t;
+-----+-------+-----+
| c1 | c2 | c3 |
+-----+-------+-----+
| 1 | true | abc |
| 100 | false | xyz |
+-----+-------+-----+

例如,你可能使用一个类似这些字面常量或函数返回值构造的小表,作为涉及到连接或 UNION ALL 操作的长 SQL 语句的一部分。

Views

视图是一个轻量级的逻辑结构,是查询的别名。你可以在查询(SELECT 语句或 INSERT 语句中的 SELECT 部分)中通常使用一个表名的位置使用视图名代替。

视图能够:

  • 建立细粒度的(fine-grained)安全,用户可以查询表中的一部分列而无法查询其他的列。参见 Controlling Access at the Column Level through Views 了解详细信息
  • 以紧凑而简单的语法执行复杂查询:
    -- 创建一个复杂的报表查询,将其加入到 CREATE VIEW 语句...
    create view v1 as select c1, c2, avg(c3) from t1 group by c3 order by c1 desc limit 10;
    -- ... 现在你可以只用 1 行代码生成报表
    select * from v1;
  • 通过避免在多种语言的多个应用中重复使用的复杂查询来减少维护量
    create view v2 as select t1.c1, t1.c2, t2.c3 from t1 join t2 on (t1.id = t2.id);
    -- 下面简单的查询比上面复杂的查询嵌入到报表应用安全
    -- 即使底层表结构变化了,视图的定义仍可以保持稳定
    select c1, c2, c3 from v2;
  • 在原始查询之上,添加新的子句、select-list 表达式、函数调用、等等,建立一个新的、更精致的查询:
    create view average_price_by_category as select category, avg(price) as avg_price from products group by category;
    create view expensive_categories as select category, avg_price from average_price_by_category order by avg_price desc limit 10000;
    create view top_10_expensive_categories as select category, avg_price from expensive_categories limit 10;

    这一技术让你创建几个或多或少不同粒度的相同查询,在合适的时候在它们之间切换(This technique lets you build up several more or less granular variations of the same query, and switch between them when appropriate)。

  • 为表、列、连接的结果集等等设置直观的别名:
    -- 原始表可能有从历史系统集成下来的神秘名称(The original tables might have cryptic names inherited from a legacy system)
    create view action_items as select rrptsk as assignee, treq as due_date, dmisc as notes from vxy_t1_br;
    -- 你可以为了兼容性保留原有名称,而使用更直观的名称建立新应用
    select assignee, due_date, notes from action_items;
  • 与其他使用不同文件格式、分区方案、等等,不需要数据复制或转换的停机时间的交换表:
    create table slow (x int, s string) stored as textfile;
    create view report as select s from slow where x between 20 and 30;
    -- 因为低效的表定义,查询缓慢,但是正常工作(Query is kind of slow due to inefficient table definition, but it works)
    select * from report; create table fast (s string) partitioned by (x int) stored as parquet;
    -- ...从 SLOW 复制数据到 FAST。针对 REPORT 视图的查询继续工作... -- 修改视图定义之后,因为新表采用分区、二进制文件格式、压缩,查询会变快
    alter view report as select s from fast where x between 20 and 30;
    select * from report;
  • 避免编写冗长的子查询和在许多查询中使用的相同子查询

配置视图的相关 SQL 语句是 CREATE VIEW StatementALTER VIEW StatementDROP VIEW Statement。你可以在查询数据时 (SELECT Statement) 和从一个表向另一个表复制数据时(INSERT Statement)使用视图。WITH 子句创建了一个旨在单个查询中存在的内联视图(inline view)。

[localhost:21000] > create view trivial as select * from customer;
[localhost:21000] > create view some_columns as select c_first_name, c_last_name, c_login from customer;
[localhost:21000] > select * from some_columns limit 5;
Query finished, fetching results ...
+--------------+-------------+---------+
| c_first_name | c_last_name | c_login |
+--------------+-------------+---------+
| Javier | Lewis | |
| Amy | Moses | |
| Latisha | Hamilton | |
| Michael | White | |
| Robert | Moran | |
+--------------+-------------+---------+
[localhost:21000] > create view ordered_results as select * from some_columns order by c_last_name desc, c_first_name desc limit 1000;
[localhost:21000] > select * from ordered_results limit 5;
Query: select * from ordered_results limit 5
Query finished, fetching results ...
+--------------+-------------+---------+
| c_first_name | c_last_name | c_login |
+--------------+-------------+---------+
| Thomas | Zuniga | |
| Sarah | Zuniga | |
| Norma | Zuniga | |
| Lloyd | Zuniga | |
| Lisa | Zuniga | |
+--------------+-------------+---------+
Returned 5 row(s) in 0.48s

之前例子中 ORDERED_RESULTS 使用了降序,因为在例子 TPCD-H 数据中,有许多行的 C_FIRST_NAME 和 C_LAST_NAME 的值为 NULL,使得名称正序排列没有用(making the lowest-ordered names unuseful in a sample query)

create view visitors_by_day as select day, count(distinct visitors) as howmany from web_traffic group by day;
create view busiest_days as select day, howmany from visitors_by_day order by howmany desc;
create view top_10_days as select day, howmany from busiest_days limit 10;
select * from top_10_days;
执行 DESCRIBE FORMATTED 语句查看视图定义,将显示原始 CREATE VIEW 语句中的查询:
[localhost:21000] > create view v1 as select * from t1;
[localhost:21000] > describe formatted v1;
Query finished, fetching results ...
+------------------------------+------------------------------+----------------------+
| name | type | comment |
+------------------------------+------------------------------+----------------------+
| # col_name | data_type | comment |
| | NULL | NULL |
| x | int | None |
| y | int | None |
| s | string | None |
| | NULL | NULL |
| # Detailed Table Information | NULL | NULL |
| Database: | views | NULL |
| Owner: | cloudera | NULL |
| CreateTime: | Mon Jul 08 15:56:27 EDT 2013 | NULL |
| LastAccessTime: | UNKNOWN | NULL |
| Protect Mode: | None | NULL |
| Retention: | 0 | NULL |
| Table Type: | VIRTUAL_VIEW | NULL |
| Table Parameters: | NULL | NULL |
| | transient_lastDdlTime | 1373313387 |
| | NULL | NULL |
| # Storage Information | NULL | NULL |
| SerDe Library: | null | NULL |
| InputFormat: | null | NULL |
| OutputFormat: | null | NULL |
| Compressed: | No | NULL |
| Num Buckets: | 0 | NULL |
| Bucket Columns: | [] | NULL |
| Sort Columns: | [] | NULL |
| | NULL | NULL |
| # View Information | NULL | NULL | | View Original Text: | SELECT * FROM t1 | NULL | | View Expanded Text: | SELECT * FROM t1 | NULL | +------------------------------+------------------------------+----------------------+
Returned 29 row(s) in 0.05s

限制:

  • Impala 中无法想视图中插入数据(在一些数据库系统中,支持这一操作并向基础表中插入数据)。你可以在 INSERT 语句的 右侧 SELECT 部分使用视图
  • 假如视图是基于分区表的,任意分区的修剪通过原始查询中子句决定。假如视图上的查询包含额外的引用了分区键列的 WHERE 子句,Impala 不会自动修剪添加的列(If a view applies to a partitioned table, any partition pruning is determined by the clauses in the original query. Impala does not prune additional columns if the query on the view includes extra WHERE clauses referencing the partition key columns)

WITH 子句

可以添加到 SELECT 语句之前的子句,用于定义复杂的、在之后的 SELECT 中会多次引用的表达式。与 CREATE VIEW 类似,除了在 WITH 子句中定义的的表名和列名在查询完成后不会保存下来,并且不会实际使用的表或视图的名称冲突。也被称为 "子查询分解(subquery factoring)"。

你可以使用子查询重写查询,就跟 WITH 子句一样工作。WITH 子句的目的是:

  • 查询中更少重复,更方便和易于维护。通常用于涉及 UNION, joins,聚合函数、类似的复杂表达式多次被引用的查询(Typically used with queries involving UNION, joins, or aggregation functions where the similar complicated expressions are referenced multiple times.)
  • 通过抽出查询中最复杂的部分作为单独的一块,SQL 代码更容易阅读和理解
  • 提高与支持这一语句的其他数据库系统的兼容性(主要是 Oracle 数据库)
    Impala SQL 语言元素(翻译)  Note:

    Impala 中 WITH 子句不支持在 WITH 中递归查询,其他数据库系统可能支持

Standards compliance: Introduced in SQL:1999.

Examples:

-- Define 2 subqueries that can be referenced from the body of a longer query.
with t1 as (select 1), t2 as (select 2) insert into tab select * from t1 union all select * from t2; -- Define one subquery at the outer level, and another at the inner level as part of the
-- initial stage of the UNION ALL query.
with t1 as (select 1) (with t2 as (select 2) select * from t2) union all select * from t1;
上一篇:LaTeX排版指南


下一篇:PHP的通过CURL或file_get_contents请求第三方URL