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個。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章