MaxCompute SQL概述及DDL常用命令

MaxCompute SQL概述

MaxCompute SQL适用于海量数据(GB、TB、EB级别)、离线批量计算的场合。MaxCompute作业提交后会有几十秒到数分钟不等的排队调度,所以适合处理运行批作业:一次作业批量处理海量数据,不适合直接对接需要每秒处理几千至数万笔事务的前台业务系统。

MaxCompute SQL采用的是类似于SQL的语法。它的语法是标准语法ANSI SQL92的一个子集,并有自己的扩展。但不能因此简单地把MaxCompute等价成一个数据库,它在很多方面并不具备数据库的特征,如事务、主键约束、索引等,更多差异请参见与其他SQL语法的差异。目前在MaxCompute中允许的最大SQL长度是2MB。

MaxCompute SQL使用时具有一定的限制,具体见:SQL使用限制项

MaxCompute SQL运算符用于执行程序代码运算,包括四种类型运算符:关系运算符、算术运算符、位运算符、逻辑运算符。具体参见:MaxCompute SQL运算符

关键字

MaxCompute将SQL语句的关键字作为保留字。在对表、列或是分区命名时如若使用关键字,需给关键字加``符号进行转义,否则会报错。保留字不区分大小写。

%    &    &&    (    )    *    +  
 -    .    /    ;    <    <=    <>  
 =    >    >=    ?    ADD    ALL    ALTER  
 AND  AS    ASC    BETWEEN    BIGINT    BOOLEAN    BY  
 CASE CAST  COLUMN    COMMENT    CREATE    DESC    DISTINCT  
 DISTRIBUTE    DOUBLE    DROP    ELSE    FALSE    FROM    FULL  
 GROUP    IF    IN    INSERT    INTO    IS    JOIN  
 LEFT    LIFECYCLE    LIKE    LIMIT    MAPJOIN    NOT    NULL  
 ON    OR    ORDER    OUTER    OVERWRITE    PARTITION    RENAME  
 REPLACE    RIGHT    RLIKE    SELECT    SORT    STRING    TABLE  
 THEN    TOUCH    TRUE    UNION    VIEW    WHEN    WHERE

类型转换说明

MaxCompute SQL允许数据类型之间的转换,类型转换方式包括显式类型转换和隐式类型转换。更多详情请参见类型转换

  • 显式类型转换:是指用cast函数将一种数据类型的值转换为另一种类型的值的行为。关于CAST的介绍请参见其他函数
  • 隐式类型转换:是指在运行时,由MaxCompute依据上下文使用环境及类型转换规则自动进行的类型转换。隐式转换作用域包括各种运算符、内建函数等。

SQL DDL常用命令

MaxCompute DDL(Database Developmemnt Language)包括如下几个方面:

  • 表操作
  • 生命周期操作
  • 分区操作
  • 视图操作

表操作

包括创建表、查看表信息、查看建表语句、删除表、清空非分区表数据、修改表名称、修改表Owner、修改表注释、修改表的修改时间等。

创建表

创建表的语法格式,如下所示。

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
[(col_name data_type [DEFAULT value] [COMMENT col_comment], ...)]
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]
[CLUSTERED BY (col_name [, col_name, ...]) [SORTED BY (col_name [ASC | DESC] [, col_name [ASC | DESC] ...])] INTO number_of_buckets BUCKETS] -- 用于创建Hash Clustering表时设置表的Shuffle和Sort属性。
[STORED BY StorageHandler] -- 仅限外部表。
[WITH SERDEPROPERTIES (Options)] -- 仅限外部表。
[LOCATION OSSLocation]; -- 仅限外部表。
[LIFECYCLE days]
[AS select_statement]
 CREATE TABLE [IF NOT EXISTS] table_name
 LIKE existing_table_name
  • 创建表时,如果不指定if not exists选项而存在同名表,则返回出错。若指定此选项,则无论是否存在同名表,即使原表结构与要创建的目标表结构不一致,均返回成功。已存在的同名表的元信息不会被改动。
  • 表名与列名均对大小写不敏感,不能有特殊字符,只能用英文的a-z、A-Z及数字和下划线_,且建议以字母开头,名称的长度不超过128字节。单表的列定义个数最多1200个。
  • 数据类型:BIGINT、DOUBLE、BOOLEAN、DATETIME、DECIMAL和STRING等。
  • DEFAULT value 指定列的默认值,当INSERT操作不指定该列时,该列写入默认值。
  • partitioned by指定表的分区字段,目前支持TINYINT、SMALLINT、INT、BIGINT、VARCHAR和STRING类型。
    • 分区值不允许有双字节字符(如中文),必须是以英文字母a-z、A-Z开始,后可跟字母或者数字,名称的长度不超过128字节。当利用分区字段对表进行分区时,新增分区、更新分区内数据和读取分区数据均不需要做全表扫描,可以提高处理效率。
  • LIFECYCLE是表的生命周期,单位:天。create table like语句不会复制源表的生命周期属性。
  • clustered by指定Hash Key。MaxCompute将对指定列进行Hash运算,按照Hash值分散到各个Bucket中。
    • 为避免数据倾斜和热点,取得较好的并行执行效果,clustered by列适宜选择取值范围大,重复键值少的列。此外,为了达到join优化的目的,也应该考虑选取常用的Join/Aggregation Key,即类似于传统数据库中的主键。
    • sorted by用于指定在Bucket内字段的排序方式。建议sorted byclustered by一致,以取得较好的性能。此外,当sorted by子句指定之后,MaxCompute将自动生成索引,并且在查询的时候利用索引来加快执行。
    • INTO number_of_buckets BUCKETS指定了哈希桶的数目。这个数字必须填写,且由数据量大小来决定。此外,缺省条件下MaxCompute只能支持最多1111个Reducer,所以此处最多也只支持1111个哈希桶。
    • Hash Clustering表的限制:
      • 不支持insert into,只能通过insert overwrite来添加数据。
      • 不支持Tunnel直接Upload到Range Cluster表,因为Tunnel上传数据是无序的。

1. 使用create table创建表:假设创建表sale_detail来保存销售记录,该表使用销售时间sale_date和销售区域 region作为分区列,建表语句如下所示:

-- 创建一张分区表sale_detail
create table if not exists sale_detail
(
    shop_name     string,
    customer_id   string,
    total_price   double
)
partitioned by (sale_date string,region string);

查看该表结构如下:

desc sale_detail;

+------------------------------------------------------------------------------------+
| Owner: [email protected] | Project: yitian_bj_mc                                |
| TableComment:                                                                      |
+------------------------------------------------------------------------------------+
| CreateTime:               2020-04-17 15:08:42                                      |
| LastDDLTime:              2020-04-17 15:08:42                                      |
| LastModifiedTime:         2020-04-17 15:08:42                                      |
+------------------------------------------------------------------------------------+
| InternalTable: YES      | Size: 0                                                  |
+------------------------------------------------------------------------------------+
| Native Columns:                                                                    |
+------------------------------------------------------------------------------------+
| Field           | Type       | Label | Comment                                     |
+------------------------------------------------------------------------------------+
| shop_name       | string     |       |                                             |
| customer_id     | string     |       |                                             |
| total_price     | double     |       |                                             |
+------------------------------------------------------------------------------------+
| Partition Columns:                                                                 |
+------------------------------------------------------------------------------------+
| sale_date       | string     |                                                     |
| region          | string     |                                                     |
+------------------------------------------------------------------------------------+

 2. 使用create table...as select...语句再创建一个表,并在建表的同时将数据复制到新表中

create table sale_detail_ctas1 as
select * from sale_detail;

此时,如果表sale_detail中存在数据,上面的示例会将表sale_detail的数据全部复制到表sale_detail_ctas1

注意:此处sale_detail是一张分区表,而通过create table...as select...语句创建的表sale_detail_ctas1不会复制分区属性,只会把源表的分区列作为目标表的一般列处理。即sale_detail_ctas1是一个含有5列的非分区表。

此外,执行上述SQL,需要设置全表扫描,否则会提示异常。命令如下:

-- 设置允许全表扫描
setproject odps.sql.allow.fullscan=true;

查看sale_detail_ctas1的结构如下:

desc sale_detail_ctas1;
+------------------------------------------------------------------------------------+
| Owner: [email protected] | Project: yitian_bj_mc                                |
| TableComment:                                                                      |
+------------------------------------------------------------------------------------+
| CreateTime:               2020-04-17 15:11:02                                      |
| LastDDLTime:              2020-04-17 15:11:02                                      |
| LastModifiedTime:         2020-04-17 15:11:02                                      |
+------------------------------------------------------------------------------------+
| InternalTable: YES      | Size: 0                                                  |
+------------------------------------------------------------------------------------+
| Native Columns:                                                                    |
+------------------------------------------------------------------------------------+
| Field           | Type       | Label | Comment                                     |
+------------------------------------------------------------------------------------+
| shop_name       | string     |       |                                             |
| customer_id     | string     |       |                                             |
| total_price     | double     |       |                                             |
| sale_date       | string     |       |                                             |
| region          | string     |       |                                             |
+------------------------------------------------------------------------------------+

3. 在create table...as select...语句中,如果在select子句中使用常量作为列的值,建议您指定列的名字: 

-- 为创建的常量列指定名称,分别为sale_date和region
CREATE TABLE sale_detail_ctas2
AS
SELECT shop_name, customer_id, total_price, '2013' AS sale_date, 'China' AS region
FROM sale_detail;

如果不指定,直接使用如下命令创建表,则新增的第四、五列类似于_c5_c6:

CREATE TABLE sale_detail_ctas3
AS
SELECT shop_name, customer_id, total_price, '2013', 'China'
FROM sale_detail;

4. 如果希望源表和目标表具有相同的表结构,可以尝试使用create table...like操作:

create table sale_detail_like like sale_detail;

此时,sale_detail_like的表结构与sale_detail完全相同。除生命周期属性外,列名、列注释以及表注释等均相同。但sale_detail中的数据不会被复制到sale_detail_like表中。

5. 创建Hash Clustering表示例如下

--创建Hash Clustering非分区表。
CREATE TABLE cluster_table_1 (
  a string, 
  b string, 
  c bigint
) 
CLUSTERED BY (c) SORTED by (c) INTO 1024 BUCKETS;

--创建Hash Clustering分区表。
CREATE TABLE cluster_table_2 (
  a string, 
  b string, 
  c bigint
) 
PARTITIONED BY (dt string) 
CLUSTERED BY (c) SORTED by (c) INTO 1024 BUCKETS; 

查看表信息

该命令已经在上述使用,命令结构如下:

desc <table_name>;
desc extended <table_name>; --查看外部表信息。

除了以上基本的使用,desc命令还有如下的使用方式:

使用DESC EXTENDED table_name;命令查看Hash Clustering Table的Clustering属性,如下所示,Clustering属性将显示在Extended Info中。

查看建表语句

查看建表语句的语法格式如下,该命令可生成创建Table的SQL DDL语句,方便您通过SQL重建Schema。

SHOW CREATE TABLE <table_name>;

删除表

删除表的语法格式如下。

DROP TABLE [IF EXISTS] table_name;
  • 如果不指定if exists选项而表不存在,则返回异常。若指定此选项,无论表是否存在,皆返回成功。

使用示例:

create table sale_detail_drop like sale_detail;
    drop table sale_detail_drop;
    --若表存在,成功返回;若不存在,异常返回。
    drop table if exists sale_detail_drop2;
    --无论是否存在sale_detail_drop2表,均成功返回。

清空非分区表数据

将指定的非分区表中的数据清空,该命令不支持分区表。对于分区表,可以用ALTER TABLE table_name DROP PARTITION的方式将分区里的数据清除。

清空非分区表里的数据的语法格式如下。

TRUNCATE TABLE table_name;

修改表名称

重命名表的语法格式如下。

ALTER TABLE table_name RENAME TO new_table_name;

使用示例: 

create table sale_detail_rename1 like sale_detail;
alter table sale_detail_rename1 rename to sale_detail_rename2;

修改表Owner

MaxCompute SQL支持通过changeowner命令来修改表的拥有人(表Owner),相应的语法格式如下。

alter table table_name changeowner to '[email protected]';

修改表注释

修改表的注释的语法格式如下:

ALTER TABLE table_name SET COMMENT 'tbl comment';

使用示例:

alter table sale_detail set comment 'new coments for table sale_detail';

修改表的修改时间

MaxCompute SQL提供touch操作用来修改表的LastDataModifiedTime,可将表的LastDataModifiedTime修改为当前时间。修改表的修改时间的语法格式,如下所示:

ALTER TABLE table_name TOUCH;

查询表数据

select语句的使用较多,使用另外文章进行说明: MaxCompute SQL中select语句使用详情

生命周期操作

  • 在创建表的时候指定生命周期。生命周期只能在表级别设置,不能在分区级别设置。分区表设置生命周期后,生命周期也会在分区级别生效。
  • 在MaxCompute中,每当表的数据被修改后,表的LastDataModifiedTime将会被更新。因此,MaxCompute会根据每张表的LastDataModifiedTime以及生命周期的设置来判断是否要回收此表。
  • 如果表是非分区表,自最后一次数据被修改开始计算,经过days天后数据仍未被改动,则此表无需您干预,将会被MaxCompute自动回收(类似drop table操作)。
  • 如果表是分区表,则根据各分区的LastDataModifiedTime判断该分区是否该被回收。
  • 不同于非分区表,分区表的最后一个分区被回收后,该表不会被删除。
  • 非分区表不支持取消生命周期,只能修改生命周期。分区表可以取消某个具体分区的生命周期。

修改生命周期

-- days:生命周期时间,只能为正整数,单位为天。 
ALTER TABLE table_name SET lifecycle days;

使用示例:

-- 新建test_lifecycle表,生命周期为100天。
CREATE TABLE test_lifecycle(key string) lifecycle 100;
-- 修改test_lifecycle表,将生命周期设为50天。
ALTER TABLE test_lifecycle SET lifecycle 50;

禁止/恢复生命周期

ALTER TABLE table_name [partition_spec] ENABLE|DISABLE LIFECYCLE;
  • table_name:表名称。
  • partition_spec:分区名称。
  • DISABLE LIFECYCLE:禁止分区表、分区表指定分区的生命周期功能。
  • ENABLE LIFECYCLE:撤销对表、分区生命周期的禁止,恢复表、分区生命周期功能。

 使用示例:

--禁止表trans的生命周期功能。
ALTER TABLE trans DISABLE LIFECYCLE;
--禁止表trans中时间为20141111分区生命周期功能。
ALTER TABLE trans PARTITION(dt='20141111') DISABLE LIFECYCLE;

分区和列操作

添加分区操作

ALTER TABLE table_name ADD [IF NOT EXISTS] PARTITION partition_spec;
partition_spec:(partition_col1 = partition_col_value1, partition_col2 = partiton_col_value2, ...)
  • table_name:需要新增分区的表名称。
  • IF NOT EXISTS:如果未指定IF NOT EXISTS而同名的分区已存在,则返回报错。
  • partition_spec:新增的分区名称,分区名必须小写。(分区字段不包含在表的原有字段中)

使用示例:

--给表sale_detail添加分区,用来存储2013年12月杭州地区的销售记录。
alter table sale_detail add if not exists partition (sale_date='201312', region='hangzhou');

--给表sale_detail添加分区,用来存储2013年12月上海地区的销售记录。
alter table sale_detail add if not exists partition (sale_date='201312', region='shanghai');

--给表sale_detail添加分区,仅指定一个分区sale_date,出错返回。
alter table sale_detail add if not exists partition(sale_date='20111011');

-- 给表sale_detail添加分区,仅指定一个分区region,出错返回。
alter table sale_detail add if not exists partition(region='shanghai');

删除分区操作

ALTER TABLE table_name DROP [IF EXISTS] PARTITION partition_spec;
partition_spec:(partition_col1 = partition_col_value1, partition_col2 = partiton_col_value2, ...)
  • table_name:需要删除分区的表名称。
  • IF EXISTS:如果未指定IF EXISTS且分区不存在,则返回报错。
  • partition_spec:删除的分区名称,分区名必须小写。

使用示例:

--从表sale_detail中删除2013年12月杭州分区的销售记录。
alter table sale_detail drop if exists partition(sale_date='201312',region='hangzhou'); 

添加列操作

1. 添加列:

ALTER TABLE table_name ADD COLUMNS (col_name1 type1,col_name2 type2...);

2. 同时添加列和注释:

ALTER TABLE table_name ADD COLUMNS (col_name1 type1 comment 'XXX',col_name2 type2 comment 'XXX');
  • table_name:需要新增列的表名称。添加的新列不支持指定顺序,默认在最后一列。
  • col_name, type ,comment:新增的列名称以及对应的数据类型和注释。

修改列名操作

ALTER TABLE table_name CHANGE COLUMN old_col_name RENAME TO new_col_name;
  • table_name:需要修改列名的表名称。
  • old_col_name:需要修改的列名称。old_col_name必须是已存在的列。
  • new_col_name:新的列名称。表中不能有名为new_col_name的列。

修改分区值

MaxCompute SQL支持通过RENAME操作更改对应表的分区值。

ALTER TABLE table_name PARTITION (partition_col1 = partition_col_value1, partition_col2 = partiton_col_value2, ...) 
RENAME TO PARTITION (partition_col1 = partition_col_newvalue1, partition_col2 = partiton_col_newvalue2, ...);
  • table_name:需要修改分区值的表名称。如果此表不存在,则返回报错。
  • partition_col = partition_col_value:表的分区名称以及对应的分区值。
  • partition_col = partition_col_newvalue:表的分区名称和修改后新的分区值。

合并分区

MaxCompute SQL提供MERGE PARTITION对分区进行合并,即同一个表下多个分区数据合并成一个分区,同时删除被合并的分区维度的信息,把数据移动到指定分区。

ALTER TABLE <tableName> MERGE [IF EXISTS] PARTITION(<predicate>) [, PARTITION(<predicate2>) ...] OVERWRITE PARTITION(<fullPartitionSpec>) [PURGE];
  • 如果分区不存在且没有指定IF EXISTS,则报错。
  • 如果指定IF EXISTS 后不存在满足MERGE条件的分区,则不生成新分区。
  • 如果运行过程中出现源数据被并发修改(包括INSERT,RENAME,DROP)时,即使指定IF EXISTS也会报错。
  • 不支持外表, 不支持SHARD表,对于CLUSTERED表合并后的分区文件会消除CLUSTERED属性。
  • 一次性合并分区数量限制:4000个。
发布了330 篇原创文章 · 获赞 71 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/yitian_z/article/details/105577170