CREATE TABLE創建分區表與復制表
本文介紹云原生數據倉庫 AnalyticDB MySQL 版的CREATE TABLE
建表語法。您將了解到如何創建分區表和復制表,以及如何定義表的分布鍵、分區鍵、索引、生命周期、冷熱數據分層等。
建表前,您可以通過下圖中的示例,了解關于表的幾個重要概念,包括分片、分區、聚集索引。
語法
CREATE TABLE [IF NOT EXISTS] table_name
({column_name column_type [column_attributes] [ column_constraints ] [COMMENT 'column_comment']
| table_constraints}
[, ... ])
[table_attribute]
[partition_options]
[storage_policy]
[block_size]
[engine]
[rt_engine]
[table_properties]
[AS query_expr]
[COMMENT 'table_comment']
column_attributes:
[DEFAULT {constant | CURRENT_TIMESTAMP}]
[AUTO_INCREMENT]
column_constraints:
[{NOT NULL|NULL} ]
[PRIMARY KEY]
table_constraints:
[{INDEX|KEY} [index_name] (column_name,...)]
[{INDEX|KEY} [index_name] (column_name->'$[*]')]
[FULLTEXT [INDEX|KEY] [index_name] (column_name) [index_option]] [,...]
[PRIMARY KEY [index_name] (column_name,...)]
[CLUSTERED KEY [index_name] (column_name,...)]
[[CONSTRAINT [symbol]] FOREIGN KEY (fk_column_name) REFERENCES pk_table_name (pk_column_name)][,...]
[ANN INDEX [index_name] (column_name,...) [index_option]] [,...]
table_attribute:
DISTRIBUTED BY HASH(column_name,...) | DISTRIBUTED BY BROADCAST
partition_options:
PARTITION BY
{VALUE(column_name) | VALUE(date_format(column_name, 'format'))}
LIFECYCLE N
storage_policy:
STORAGE_POLICY= {'HOT'|'COLD'|'MIXED' {hot_partition_count=N}}
block_size:
BLOCK_SIZE= VALUE
engine:
ENGINE= 'XUANWU|XUANWU_V2'
參數
table_name、column_name、column_type、COMMENT
column_attributes(默認值與自增列)
DEFAULT {constant | CURRENT_TIMESTAMP}
定義列的默認值。僅支持常量或CURRENT_TIMESTAMP函數。不支持其他函數和變量表達式。
如果未指定默認值,則列的默認值為NULL
。
AUTO_INCREMENT
定義自增列。 自增列的數據類型必須是BIGINT
類型。
AnalyticDB for MySQL為自增列提供唯一值,但自增列的值不是順序遞增,且不支持從1開始遞增。
column_constraints(非空與主鍵)
NOT NULL
定義了NOT NULL
的列,值不能為NULL
。不定義NOT NULL
或定義了NULL
時,值可以為NULL
。
PRIMARY KEY
定義主鍵。在列約束(column_constraints)中,只能定義單一列作為主鍵,例如id BIGINT NOT NULL PRIMARY KEY
。如需多個列作為主鍵,請在表約束(table_constraints)中定義復合主鍵。
table_constraints(索引)
AnalyticDB for MySQL支持多種索引,包括INDEX索引、主鍵索引、聚集索引、外鍵索引、全文索引、向量索引等。一個表可以有一種或多種索引。
INDEX | KEY
定義普通索引。INDEX和KEY作用相同。
默認情況下,AnalyticDB for MySQL自動為全表所有列創建索引。但是,如果您在建表時手動指定為某一列或某幾列創建索引(例如INDEX (id)
),則AnalyticDB for MySQL不會再為表中其他列自動創建索引。
PRIMARY KEY
定義主鍵索引。
基本使用:
每個表只能有一個主鍵。
主鍵可以是單個列或多個列的組合,例如
PRIMARY KEY (id)
或PRIMARY KEY (id,name)
。主鍵中必須包含分布鍵和分區鍵,并且建議將分布鍵和分區鍵放在主鍵的前部。
注意事項:
無主鍵的表,不能執行DELETE和UPDATE操作。
未定義主鍵,會有以下行為:
如果未定義主鍵和分布鍵,AnalyticDB for MySQL將自動添加一個列
__adb_auto_id__
作為表的主鍵和分布鍵。如果未定義主鍵,但定義了分布鍵,AnalyticDB for MySQL不會自動添加主鍵。
建表后,不能增加、減少或變更主鍵列。
調優建議:推薦使用數值類型的列作為主鍵,并盡量減少主鍵包含的列的個數,以獲得較好的性能。
主鍵包含的列過多,可能導致:
數據寫入時,AnalyticDB for MySQL檢查主鍵是否重復,將消耗更多的CPU和IO資源。
主鍵索引將占用更多的磁盤空間。您可以使用空間分析功能,查看主鍵索引占用的磁盤空間。
主鍵包含的列越多,BUILD任務會越慢。
CLUSTERED KEY
定義聚集索引。聚集索引是分區級別的,它決定了數據的物理存儲順序,即分區內的數據會按聚集索引的鍵值進行排序,按順序存儲。聚集索引的鍵值相同或相近的數據存儲在相同或相近數據塊。在范圍查詢或等值查詢中,如果查詢條件與聚集索引列一致,存儲引擎可快速讀取連續的數據塊,這樣可以減少磁盤的I/O,加快數據讀取的速度。
適用場景:
聚集索引既適用于范圍查詢,也適用于等值查詢。高頻出現在范圍查詢條件和等值查詢條件的列,可以作為聚集索引。
當查詢條件涉及的列與聚集索引列完全一致或部分一致時,可以加快數據讀取的效率。例如,在SaaS類應用中,用戶通常只訪問自己的數據,用戶ID可以作為聚集索引,保證同一用戶ID的數據連續存儲在相同或相鄰的數據塊中,數據讀取更快。
基本使用:
每個表中只能有一個聚集索引。
聚集索引可以基于單個列創建(例如
CLUSTERED KEY index(id)
),也可以基于多個列創建(例如CLUSTERED KEY index(id,name)
)。當聚集索引鍵涉及多個列時,數據會先根據第一個列的值排序,在第一個列的值相同時,按第二個列的值進行次級排序。所以CLUSTERED KEY index(id,name)
與CLUSTERED KEY index(name,id)
是不同的聚集索引。如果字段值較長,例如長達十幾KB或幾十KB的字符串,則不建議聚集索引采用該字段,避免影響排序性能。
FULLTEXT INDEX | FULLTEXT KEY
定義全文索引。FULLTEXT INDEX與FULLTEXT KEY作用相同。關于全文索引的更多介紹,請參見創建全文索引。
語法:[FULLTEXT [INDEX|KEY] [index_name] (column_name) [index_option]] [,...]
參數說明:
index_name:全文索引名稱。
column_name:全文索引的列。列的類型必須是VARCHAR類型。
index_option:指定全文索引的分詞器和自定義詞典。非必填。
WITH ANALYZER analyzer_name
:指定全文索引的分詞器。分詞器取值和用法,請參見全文索引的分詞器。WITH DICT tbl_dict_name
:指定全文索引的自定義詞典。自定義詞典的詳細用法,請參見全文索引的自定義詞典。
FOREIGN KEY
定義外鍵索引。外鍵索引用于消除不必要的JOIN,關于JOIN消除的詳情,請參見通過主外鍵約束消除多余的JOIN。
版本說明:
AnalyticDB for MySQL集群內核版本需為3.1.10或以上。
查看企業版或湖倉版集群的內核版本,請執行SELECT adb_version();
。如需升級內核版本,請聯系技術支持。
語法:[[CONSTRAINT [symbol]] FOREIGN KEY (fk_column_name) REFERENCES pk_table_name (pk_column_name)][,...]
參數說明:
symbol:可選項,外鍵約束名,在表內唯一。不指定時,解析器將會在外鍵列名后面自動補充后綴_fk用作外鍵約束名。
fk_column_name:指定外鍵列。外鍵列需要在建表語句中定義。
pk_table_name:指定主表名。主表必須已存在。
pk_column_name:指定外鍵約束列,該列必須存在且為主表的主鍵列。
基本使用:
每個表可以有多個外鍵索引。
不支持復合的外鍵索引,即不支持多個列組成的外鍵索引,例如:
FOREIGN KEY (sr_item_sk, sr_ticket_number) REFERENCES store_sales(ss_item_sk,d_date_sk)
。AnalyticDB for MySQL不會進行數據的約束檢查。您需要自行確保主表的主鍵和從表的外鍵之間的數據約束關系。
外表不支持創建外鍵約束。
ANN INDEX
定義向量索引。關于向量索引和向量檢索的更多介紹,請參見向量檢索。
語法:[ANN INDEX [index_name] (column_name,...) [index_option]] [,...]
參數說明:
index_name:向量索引的名稱。
column_name:向量列的列名。向量列的類型需為array<float>、array<smallint>、array<byte>,且需指定向量列的維數,向量列的定義示例:
feature array<float>(4)
。index_option:向量索引的屬性。
algorithm
:向量距離計算公式使用的算法。取值僅支持HNSW_PQ,適用于單表數據量在百萬級別到千萬級別之間,對向量維度敏感的中等規模數據量場景。dis_function
:向量距離計算公式。取值僅支持SquaredL2。計算公式:(x1-y1)^2+(x2-y2)^2+…
。
JSON INDEX
定義JSON索引或JSON Array索引。更多介紹,請參見JSON索引。
JSON索引
版本說明:
3.1.5.10及以上內核版本的集群,創建表后不會自動創建JSON索引,您需手動創建JSON索引。
3.1.5.10以下內核版本的集群,創建表后會自動為JSON列創建JSON索引。
查看企業版或湖倉版集群的內核版本,請執行SELECT adb_version();
。如需升級內核版本,請聯系技術支持。
語法:[INDEX [index_name] (column_name|column_name->'$.json_path'.)]
參數說明:
index_name:索引的名稱。
column_name|column_name->'$.json_path':
column_name:JSON索引的列。
column_name->'$.json_path':JSON索引的列及其指定的屬性鍵。每一個JSON索引只能有一個JSON列的一個屬性鍵。
重要僅3.1.6.8及以上內核版本的集群支持
column_name->'$.json_path
。查看企業版、基礎版或湖倉版集群的內核版本,請執行
SELECT adb_version();
。如需升級內核版本,請聯系技術支持。查看和升級數倉版集群的內核版本,請參見查看和升級版本。
為JSON列中的指定屬性鍵創建索引時,若該JSON列已存在INDEX索引,需先刪除該列的INDEX索引,否則會報錯。
JSON Array索引
版本說明:
僅3.1.10.6及以上內核版本的集群支持創建JSON Array索引。
查看企業版或湖倉版集群的內核版本,請執行SELECT adb_version();
。如需升級內核版本,請聯系技術支持。
語法:[INDEX [index_name] (column_name->'$[*]')]
參數說明:
index_name:索引的名稱。
column_name->'$[*]':column_name為JSON Array索引的列。例如:vj->'$[*]'表示為vj列創建JSON Array索引。
table_attribute(分布鍵)
table_attribute決定了表的類型是普通表還是復制表。
DISTRIBUTED BY HASH,定義表為普通表。普通表能夠充分利用分布式系統的查詢優勢,提高查詢效率。普通表可存儲的數據量較大,通常可以存儲千萬條甚至千億條數據。
DISTRIBUTED BY BROADCAST,定義表為復制表。復制表會在集群的每個分片存儲一份數據,因此建議每個復制表中的數據量不宜太大,最好不超過2萬行。
DISTRIBUTED BY HASH (column_name,...)
定義表的分布鍵。定義了分布鍵的表,又稱普通表。AnalyticDB for MySQL對分布鍵的值進行哈希計算,根據計算得出的哈希值,將不同行的數據分散到不同分片(Shard),有利于提高可擴展性和查詢性能。
基本用法:
每個表只能有一個分布鍵。
一個分布鍵可以包含一個列或者多個列。
分布鍵中的列,必須包含在主鍵中。例如,分布鍵為customerid,那么主鍵也需要包含customerid。
注意事項:
創建表時未定義分布鍵,系統會根據表是否含有主鍵進行如下處理:
如果MySQL表含有主鍵,AnalyticDB for MySQL默認將主鍵作為分布鍵。
如果MySQL表不含有主鍵,AnalyticDB for MySQL將自動添加一個
__adb_auto_id__
列作為主鍵和分布鍵。
建表后,不能增加、減少或變更分布鍵列。如果需要修改分布鍵,需重新建表并遷移數據,具體操作請參見ALTER TABLE。
調優建議:
建議分布鍵包含盡可能少的列,使得分布鍵在各種復雜查詢中更加通用。
盡可能選擇高頻率出現在查詢條件中,且值分布均勻的列作為分布鍵,例如交易ID、設備ID、用戶ID或者自增列作為分布鍵。但如果查詢條件非常局限,例如列a雖然值分布均勻且高頻出現在查詢條件中,但總是以a=3的形式出現在查詢條件中,那么列a作為分布鍵會造成數據熱點,列a就不適合作為分布鍵。
盡可能將需要Join的列作為分布鍵。參與Join的兩個表,按相同的分布鍵(Join列)進行數據分布,使得兩個表相同鍵值的數據被分布到同一分片,可直接在同一分片進行Join操作,無需在分片之間進行數據傳輸,能夠有效減少查詢過程中的數據重分布,提升查詢性能。例如,需要按照顧客維度查看歷史訂單信息,可以選擇
customer_id
作為分布鍵。盡量不要選擇日期、時間和時間戳類型的列作為分布鍵,寫入時容易發生傾斜,影響寫入性能,且多數查詢通常是限定了日期或時間段,如:查詢最近一天或一個月的數據,可能會導致要查詢的數據只存在于一個節點上,無法充分利用分布式數據庫中所有節點的處理能力。建議將日期、時間類型的列作為分區鍵,具體請參見partition_options(分區鍵與生命周期)。
您可以利用數據建模診斷功能查看表的分布鍵是否合理、數據是否傾斜。詳情請參見存儲空間診斷。
DISTRIBUTED BY BROADCAST
定義復制表。復制表會在集群的每個節點存儲一份該表的全量數據,因此建議復制表的數據量不宜太大。
優點:Join查詢時,無需將復制表的數據在不同節點之間傳輸。當查詢并發量較大時,可以有效降低網絡傳輸的開銷,提高集群穩定性。
缺點:當復制表數據發生變更(插入、變更或刪除)時,變更會被廣播到集群的所有節點,確保所有節點上具有一致的數據副本,會影響整體寫入性能。因此不建議對復制表進行頻繁的增刪改等操作。
partition_options(分區鍵與生命周期)
如果設置了分布鍵后,單個分片的數據量較大,您可以定義分區鍵將分片上的數據劃分為不同的分區,加快數據過濾速度,提高查詢性能。
分區可以加快數據過濾速度,提高查詢性能。
分區裁剪。只查詢相關數據的分區,跳過無關分區,減少數據掃描,提高查詢速度。
索引的掃描性能較好。當索引的行數過大,例如超過5000萬行,索引的掃描效率就會下降。索引是分區級別的,即每個分區有一個獨立的索引。如果表沒有定義數據分區,那么表的所有數據都在一個分區中,數據量超過千萬時,索引掃描效率下降。當表定義了數據分區,數據分散在不同分片的不同分區時,每個分區索引的行數可以控制在千萬行內,可以保證掃描的性能。
提高Build的效率。Build用于將實時數據轉換成歷史數據,過程中會構建分區、構建索引、清理冗余數據等。Build任務完成,新的索引才能生效。當表沒有定義分區時,每次Build任務都是全表Build,數據越多,Build越慢,新的索引就會越晚生效,從而影響查詢性能。當表定義了分區,每次只Build有數據變更的分區,Build的時間就會縮短。
分區結合生命周期(LIFECYCLE),可以實現數據的生命周期管理。
分區結合存儲策略(storage_policy),可以實現冷熱數據分層。
PARTITION BY
指定分區鍵。
語法:PARTITION BY VALUE {(column_name) | (DATE_FORMAT(column_name, 'format'))} LIFECYCLE n
參數說明:
column_name:分區鍵。
PARTITION BY VALUE(column_name)
表示使用column_name
的值來分區。分區鍵的數據類型可以是數值類型、日期時間類型或表示數字的字符串類型。DATE_FORMAT(column_name, 'format')
:使用DATE_FORMAT
函數將日期時間類型的列轉換成指定的日期格式,再對數據分區。format僅支持年、月、日,即%Y、%y、%Y%m、%y%m、%Y%m%d、%y%m%d。建表后,format支持修改,修改方法請參見ALTER TABLE。
注意事項:
3.2.1.0以下內核版本的集群,使用
PARTITION BY
定義分區時,必須同時定義生命周期(LIFECYCLE n
),否則會報錯。3.2.1.0 及以上內核版本的集群,使用
PARTITION BY
定義分區時,生命周期(LIFECYCLE n
)為可選參數。若未配置,則分區數據不會被清理。建表后,不能增加分區鍵,也不支持增加、減少或變更修改分區鍵中的列。如果需要增加或修改分區鍵,請重新建表并遷移數據,具體操作請參見ALTER TABLE。
調優建議:
建議使用日期時間類型的字段作為分區鍵。
分區太大或太小都會影響查詢性能和寫入性能,甚至影響集群的穩定性。建議的分區內數據行數以及查看分區是否合理,請參見分區表診斷。
不建議頻繁更新歷史分區的數據,例如,如果每天頻繁更新多個歷史分區,應考慮使用的分區鍵是否合理。
LIFECYCLE n
LIFECYCLE需要與PARTITION BY
一起使用,用于管理分區的生命周期。AnalyticDB for MySQL會根據分區鍵的值,從大到小對分區排序,保留前n個分區,超出n的分區將被刪除。您可以利用LIFECYCLE定義數據的保留時長。
3.2.1.1以下內核版本,
LIFECYCLE n
定義每個分片最多保留n個分區。以分片級管理分區的生命周期時,在數據分布不均或數據量極少的情況下,可能會出現保留的總分區數多于n的情況。3.2.1.1及以上內核版本,升級后新建表按照表級管理分區的生命周期,
LIFECYCLE n
定義每個表最多保留n個分區。升級前已創建的表仍按照分片級管理分區的生命周期,LIFECYCLE n
定義每個分片最多保留n個分區。
示例:
例如,PARTITION BY VALUE (DATE_FORMAT(date, '%Y%m%d')) LIFECYCLE 30
表示,將date列轉換為yyyyMMdd的格式并對數據分區,最多保留30個分區。假設第1天的數據寫入分區20231201,第2天的數據寫入分區20231202,依次類推,第30天的數據寫入分區20231230。當第31天的數據寫入分區20231231時,因為最多只能保留30個分區,所以最小的分區(即分區20231201)將會被自動刪除。
storage_policy(存儲策略)
企業版、基礎版及湖倉版和數倉版彈性模式集群版(新版)支持指定數據的存儲策略。不同的存儲策略,數據的讀寫性能不同,數據的存儲成本也不同。
取值說明:
hot(默認值): 熱存儲,即全表所有分區的數據都存儲在SSD。性能最好,但存儲成本也最高。
cold: 冷存儲,即全表所有分區的數據都在OSS。性能比熱存儲差,但存儲成本最低。
mixed: 冷熱混合存儲,又叫冷熱分層存儲,即查詢頻率高的分區數據(又稱熱數據)存儲在SSD,查詢頻率低的分區數據(又稱冷數據)存儲在OSS,既降低存儲成本,又保證查詢性能。選擇mixed時,必須同時使用
PARTITION BY
定義分區并使用hot_partition_count
指定熱分區的數量。如未定義分區,mixed不生效,數據實際會存儲在SSD。
hot_partition_count(熱分區)
當STORAGE_POLICY='mixed'
時,需要通過hot_partition_count=n
(n為正整數)定義熱分區的數量。AnalyticDB for MySQL將根據分區鍵的值,從大到小對分區排列,最大的n個分區為熱分區,其他分區為冷分區。
如果存儲策略(STORAGE_POLICY
)的取值不是mixed,則不支持指定hot_partition_count=n
,否則會報錯。
block_size(數據塊)
Block,又叫數據塊,是數據讀寫的最小IO單元。block_size用于指定列式存儲中每個block存儲的數據行數。調整block_size會增加或減少每次IO讀取的行數,具體的影響需要結合查詢特征,例如點查詢時,若block_size較大,存儲讀block的效率會降低,此時可以適當調小block_size。
默認值說明:
復制表的block_size默認值為4096。
彈性模式集群版(新版)單機版(計算資源為32核以下),block_size默認值為8192。
其它情況下,block_size默認值為32760。當block_size為32760時,在
SHOW CREATE TABLE
時,不顯示block_size。
若不熟悉列式存儲原理,建議不要更改block_size。
engine(存儲引擎)
指定AnalyticDB for MySQL內表的存儲引擎類型,用于歷史數據分析。
取值說明:
XUANWU(默認值):若建表時未顯式指定ENGINE,則默認選擇該值。
XUANWU_V2:XUANWU引擎基礎上研發的新一代存儲引擎。僅V3.2.0及以上內核版本支持XUANWU_V2。需提前開啟XUANWU_V2引擎,方法請參見XUANWU_V2引擎介紹。
3.1.9.5以下內核版本的集群,如果在創建內表時顯式指定了
ENGINE='XUANWU'
,則需同時顯示指定table_properties='{"format":"columnstore"}'
,否則建表會失敗。了解玄武存儲引擎的介紹,請參見玄武分析型存儲引擎。
AS query_expr(CTAS)
CREATE TABLE AS query_expr表示創建表并將SELECT查詢結果寫入新創建的表。具體用法,請參見CREATE TABLE AS SELECT(CTAS)。
示例
新建分區表并設置生命周期
新建普通表customer,login_time
、customer_id
、phone_num
為復合主鍵, customer_id
為分布鍵,login_time
為分區鍵,分區的生命周期為30。
所有分區,按分區鍵login_time
的值(例如,20231202,20231201等)從大到小排序,僅保留分區鍵值最大的30個分區,當第31個分區數據寫入時,自動刪除最小的第1個分區。
假設,第1天login_time的值為20231201,第二天login_time的值為20231202,依次類推,第30天login_time的值為20231230。當第31天login_time為20231231的數據寫入時,最小的分區(即'20231201'分區)數據將會被自動刪除,從而實現只保留最近30天的數據。
CREATE TABLE customer (
customer_id BIGINT NOT NULL COMMENT '顧客ID',
customer_name VARCHAR NOT NULL COMMENT '顧客姓名',
phone_num BIGINT NOT NULL COMMENT '電話',
city_name VARCHAR NOT NULL COMMENT '所屬城市',
sex INT NOT NULL COMMENT '性別',
id_number VARCHAR NOT NULL COMMENT '身份證號碼',
home_address VARCHAR NOT NULL COMMENT '家庭住址',
office_address VARCHAR NOT NULL COMMENT '辦公地址',
age INT NOT NULL COMMENT '年齡',
login_time TIMESTAMP NOT NULL COMMENT '登錄時間',
PRIMARY KEY (login_time,customer_id,phone_num)
)
DISTRIBUTED BY HASH(customer_id)
PARTITION BY VALUE(DATE_FORMAT(login_time, '%Y%m%d')) LIFECYCLE 30
COMMENT '客戶信息表';
新建表(未定義分布鍵)
未定義分布鍵,自動將主鍵作為分布鍵
表定義了主鍵但未定義分布鍵,AnalyticDB for MySQL默認將主鍵作為分布鍵。
CREATE TABLE orders (
order_id BIGINT NOT NULL COMMENT '訂單ID',
customer_id INT NOT NULL COMMENT '顧客ID',
order_status VARCHAR(1) NOT NULL COMMENT '訂單狀態',
total_price DECIMAL(15, 2) NOT NULL COMMENT '訂單金額',
order_date DATE NOT NULL COMMENT '訂單日期',
PRIMARY KEY(order_id,order_date)
);
查詢建表語句,可以看到主鍵order_id和order_date被采納為分布鍵。
SHOW CREATE TABLE orders;
+---------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+---------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| orders | CREATE TABLE `orders` ( |
| | `order_id` bigint NOT NULL COMMENT '訂單ID', |
| | `customer_id` int NOT NULL COMMENT '顧客ID', |
| | `order_status` varchar(1) NOT NULL COMMENT '訂單狀態', |
| | `total_price` decimal(15, 2) NOT NULL COMMENT '訂單金額', |
| | `order_date` date NOT NULL COMMENT '訂單日期', |
| | PRIMARY KEY (`order_id`,`order_date`) |
| | ) DISTRIBUTED BY HASH(`order_id`,`order_date`) INDEX_ALL='Y' STORAGE_POLICY='HOT' ENGINE='XUANWU' TABLE_PROPERTIES='{"format":"columnstore"}' |
+---------+-----------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.04 sec)
未定義主鍵,自動增加主鍵
表未定義主鍵,也未定義分布鍵,AnalyticDB for MySQL將添加一個列__adb_auto_id__
作為主鍵和分布鍵。
CREATE TABLE orders_new (
order_id BIGINT NOT NULL COMMENT '訂單ID',
customer_id INT NOT NULL COMMENT '顧客ID',
order_status VARCHAR(1) NOT NULL COMMENT '訂單狀態',
total_price DECIMAL(15, 2) NOT NULL COMMENT '訂單金額',
order_date DATE NOT NULL COMMENT '訂單日期'
);
查詢建表語句,可以看到表中自動增加一個自增列__adb_auto_id__,該自增列作為表的主鍵和分布鍵。
SHOW CREATE TABLE orders_new;
+-------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| orders_new | CREATE TABLE `orders_new` ( |
| | `__adb_auto_id__` bigint AUTO_INCREMENT, |
| | `order_id` bigint NOT NULL COMMENT '訂單ID', |
| | `customer_id` int NOT NULL COMMENT '顧客ID', |
| | `order_status` varchar(1) NOT NULL COMMENT '訂單狀態', |
| | `total_price` decimal(15, 2) NOT NULL COMMENT '訂單金額', |
| | `order_date` date NOT NULL COMMENT '訂單日期', |
| | PRIMARY KEY (`__adb_auto_id__`) |
| | ) DISTRIBUTED BY HASH(`__adb_auto_id__`) INDEX_ALL='Y' STORAGE_POLICY='HOT' ENGINE='XUANWU' TABLE_PROPERTIES='{"format":"columnstore"}' |
+-------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.04 sec)
新建表(未定義分區鍵)
新建表supplier,supplier_id
為自增列,分布鍵為supplier_id
,按照supplier_id
值進行HASH分片。
CREATE TABLE supplier (
supplier_id BIGINT AUTO_INCREMENT PRIMARY KEY,
supplier_name VARCHAR,
address INT,
phone VARCHAR
)
DISTRIBUTED BY HASH(supplier_id);
定義冷熱數據存儲策略
定義冷(COLD)存儲策略
CREATE TABLE item (
order_id BIGINT NOT NULL,
item_id INT NOT NULL,
quantity DECIMAL(15, 2) NOT NULL,
discount DECIMAL(15, 2) NOT NULL,
shipdate DATE NOT NULL,
PRIMARY KEY (order_id,item_id,shipdate)
)
DISTRIBUTED BY HASH(item_id)
PARTITION BY VALUE(date_format(shipdate, '%Y%m')) LIFECYCLE 200
STORAGE_POLICY='COLD';
定義熱(HOT)存儲策略
CREATE TABLE item (
order_id BIGINT NOT NULL,
item_id INT NOT NULL,
quantity DECIMAL(15, 2) NOT NULL,
discount DECIMAL(15, 2) NOT NULL,
shipdate DECIMAL NOT NULL,
PRIMARY KEY (order_id,item_id,shipdate)
)
DISTRIBUTED BY HASH(item_id)
PARTITION BY VALUE(date_format(shipdate, '%Y%m')) LIFECYCLE 200
STORAGE_POLICY='HOT';
定義混合(MIXED)存儲策略,同時指定熱分區數量為16個
CREATE TABLE item (
order_id BIGINT NOT NULL,
item_id INT NOT NULL,
quantity DECIMAL(15, 2) NOT NULL,
discount DECIMAL(15, 2) NOT NULL,
shipdate DATE NOT NULL,
PRIMARY KEY (order_id,item_id,shipdate)
)
DISTRIBUTED BY HASH(item_id)
PARTITION BY VALUE(date_format(shipdate, '%Y%m')) LIFECYCLE 200
STORAGE_POLICY='MIXED' HOT_PARTITION_COUNT=16;
定義全文索引
為content列創建全文索引,索引名稱為fidx_c。
CREATE TABLE fulltext_tb (
id INT,
content VARCHAR,
keyword VARCHAR,
FULLTEXT INDEX fidx_c(content),
PRIMARY KEY (id)
)
DISTRIBUTED BY HASH(id);
關于創建和變更全文索引的更多內容,請參見創建全文索引。
關于全文檢索,請參見全文檢索。
定義向量索引
定義short_feature、float_feature為向量列,類型是array<float>,向量維數為4。
根據short_feature創建向量索引short_feature_index,根據float_feature創建向量索引float_feature_index。
CREATE TABLE fact_tb (
xid BIGINT NOT NULL,
cid BIGINT NOT NULL,
uid VARCHAR NOT NULL,
vid VARCHAR NOT NULL,
wid VARCHAR NOT NULL,
short_feature array<smallint>(4),
float_feature array<float>(4),
ann index short_feature_index(short_feature),
ann index float_feature_index(float_feature),
PRIMARY KEY (xid, cid, vid)
)
DISTRIBUTED BY HASH(xid) PARTITION BY VALUE(cid) LIFECYCLE 4;
更多關于向量索引和向量檢索的內容,請參見向量檢索。
定義外鍵索引
新增一個名為store_returns
的表,通過使用外鍵語法FOREIGN KEY
將sr_item_sk
列和customer
表的主鍵列customer_id
關聯起來。
CREATE TABLE store_returns (
sr_sale_id BIGINT NOT NULL PRIMARY KEY,
sr_store_sk BIGINT,
sr_item_sk BIGINT NOT NULL,
FOREIGN KEY (sr_item_sk) REFERENCES customer (customer_id)
);
定義JSON Array索引
為vj列創建JSON Array索引,索引名稱為idx_vj。
CREATE TABLE json(
id INT,
vj JSON,
INDEX idx_vj(vj->'$[*]')
)
DISTRIBUTED BY HASH(id);
關于創建和變更JSON Array索引的更多內容,請參見創建JSON Array索引和JSON Array索引。
常見問題
列屬性和列約束
自增列的值不是順序遞增,也不支持從1開始遞增。但自增列的值都是唯一值。
分布鍵、分區鍵與生命周期
根據分布鍵值的HASH結果不同,數據被分散到不同的分片上。在分片上,根據分區鍵值的不同,數據被劃分為不同的分區。示意圖如下。
創建分區表,不是必須手動指定分布鍵。如果未手動指定分布鍵,AnalyticDB for MySQL會采納主鍵作為分布鍵。無主鍵時,自動生成一列
__adb_auto_id__
作為分布鍵和主鍵。創建復制表,不需要指定分布鍵,但需要指定DISTRIBUTED BY BROADCAST,表示每個存儲節點都存儲一份全量數據。
變配不會改變集群的分片數(Shard數量)。
執行SQL查詢表的分區信息:
SELECT partition_id, --分區名
row_count, -- 分區總行數
local_data_size, --分區本地存儲所占用空間大小
index_size, -- 分區的索引大小
pk_size, --分區的主鍵索引大小
remote_data_size --分區的遠端存儲所占用空間大小
FROM information_schema.kepler_partitions
WHERE schema_name = '$DB'
AND table_name ='$TABLE'
AND partition_id > 0;
創建分區表后,查不到分區信息主要有兩個原因:
建表時,只是通過定義分區鍵設置了數據分區的規則,并沒有開始創建分區。分區由分區鍵的鍵值決定。如果表還沒寫入數據,分區鍵值為空,不會創建分區。
分區不是實時構建的。當寫入的數據BUILD完成后,才能查看到分區信息。
解決方法:
請先寫入數據,并等待BUILD任務完成。BUILD任務完成后,可以查看分區信息。
BUILD的詳細介紹以及查詢BUILD進度,請參見BUILD。
分區鍵的數據類型可以是數值類型、日期時間類型或表示數字的字符串類型。除此以外的數據類型,可能導致數據寫入報錯。
如果寫入數據時,遇到報錯partition format function error
,說明寫入分區鍵的值不符合數據類型的要求。
不能。定義分區鍵僅支持兩種方法:PARTITION BY VALUE(column)和PARTITION BY VALUE(DATE_FORMAT(column,'format'))。使用其他函數會報錯。
通過SHOW CREATE TABLE <table_name>
,查看建表語句。建表語句中顯示分區表的生命周期。
可能有兩個原因:
分區剛剛過期,尚未被刪除。過期的分區數據不會被立即刪除。當該表的BUILD任務完成后,過期的分區數據才會被刪除。
3.2.1.1以下內核版本中創建的表,LIFECYCLE的定義為一個分片上保留多少個分區。當一個分片上,實際分區數小于LIFECYCLE設定值時,可能出現該現象。在3.2.1.1及以上內核版本中新建的表,不存在該問題。
例如:
數據分布不均。假設按日期分區,分片1有分區20231201、20231202、依次類推到20231230;分片2有分區20231202、20231203、依次類推到20231231。分片1和分片2上的分區數均為30,沒有超過LIFECYCLE的設定值(30),因此分片1和分片2都不會刪除分區。查詢數據時,可以查到日期為20231201~20231231的數據。
長時間無數據寫入。假設按日期分區,分片1已有分區20231201、20231202、20231203和20231204,并且在20231204后該表沒有新的分區數據寫入。此時分片1僅有4個分區,沒有超過LIFECYCLE的設定值(30),因此不會刪除分區。在20231231后,仍然可以查到日期為20231201的數據。
不會。分區不是實時構建和清理的。表的某個分區過期后,該表需要完成BUILD,分區才會被清理。
索引
通過SHOW CREATE TABLE
查詢建表語句中定義的聚集索引。
AnalyticDB for MySQL不支持唯一索引(UNIQUE INDEX)。但AnalyticDB for MySQL的主鍵索引就是唯一索引,可以確保主鍵值在表中是唯一的。
列存
TABLE_PROPERTIES='{"format":"columnstore"}'
是固定取值,表示ENGINE中的數據是列存格式。建表時您無需手動指定該屬性。
其他
ALTER TABLE支持變更以下參數:
table_name、column_name、column_type、COMMENT
增加和刪除列(主鍵列除外)
列的默認值
NOT NULL變更為NULL
增加和刪除INDEX索引
分區函數的日期格式
生命周期
存儲策略
具體用法請參見ALTER TABLE。
其他參數在建表后無法變更。
一個AnalyticDB for MySQL集群的表數量上限如下:
企業版集群:
80000/(分片數/預留資源節點數/3)
。分片數/預留資源節點數/3
向上取整。增加預留資源節點數,可提高內表數量的上限,增加預留資源節點數請參見企業版與基礎版擴縮容。
基礎版集群:
80000/(分片數/預留資源節點數)
。(分片數/預留資源節點數)
向上取整。增加預留資源節點數,可提高內表數量的上限,增加預留資源節點數請參見企業版與基礎版擴縮容。
數倉版預留模式集群(具備1~20個節點組):
80000/(分片數/節點組數量)
。分片數/節點組數量
向上取整。增加節點組數量,可提高內表數量的上限,增加節點組數量請參見數倉版擴縮容。
數倉版彈性模式集群的內表數量上限:
[80000/(分片數/EIU數量)]*2
。分片數/EIU數量
向上取整。EIU又叫彈性IO資源。增加EIU數量,可提高內表數量的上限,增加EIU數量請參見彈性IO資源(EIU)擴容。
湖倉版集群的內表數量上限:
[80000/(分片數/存儲預留資源的組數)]*2
。一組存儲預留資源為24 ACU。假設集群的存儲預留資源為48 ACU,則存儲預留資源的組數為2。擴容存儲預留資源,可提高內表數量的上限,擴容請參見湖倉版擴縮容。
企業版、基礎版及湖倉版和數倉版彈性模式集群的外表數量上限:50萬。
查詢分片數(Shard數量):SELECT COUNT(1) FROM information_schema.kepler_meta_shards;
。不支持增加或減少分片數。關于數據分片的詳細介紹,請參見分片(Shard)。
常見報錯
原因:建表語句中定義了分區,但未設置分區的生命周期。
報錯的建表語句示例如下:
CREATE TABLE test (
id INT COMMENT '',
name VARCHAR(10) COMMENT '',
PRIMARY KEY (id, name)
)
DISTRIBUTED BY HASH(id) PARTITION BY VALUE(name);
解決方法:在建表語句中定義分區的生命周期,正確的示例如下。
CREATE TABLE test (
id INT COMMENT '',
name VARCHAR(10) COMMENT '',
PRIMARY KEY (id, name)
)
DISTRIBUTED BY HASH(id) PARTITION BY VALUE(name) LIFECYCLE 30;
僅 3.2.1.0 以下內核版本的集群會出現該報錯。
原因:AnalyticDB for MySQL集群分區數量的上限默認為102400。分區數量超過上限,會出現該報錯。
查詢集群的分區數量,方法如下。
SELECT count(partition_id)
FROM information_schema.kepler_partitions
WHERE partition_id > 0;
解決方法:您可以調整分區的粒度。例如,按天分區改為按月分區。修改分區粒度的操作,請參見ALTER TABLE。
原因:主鍵需包含分布鍵和分區鍵。如果主鍵未包含分區鍵,會出現該報錯。
SQL錯誤示例1:
CREATE TABLE test (
id INT COMMENT '',
name VARCHAR(10) COMMENT '',
PRIMARY KEY (id)
)
DISTRIBUTED BY HASH(id) PARTITION BY VALUE(name) LIFECYCLE 30;
如果未指定主鍵和分布鍵,也會出現該報錯。因為建表未指定主鍵和分布鍵時,AnalyticDB for MySQL會自動生成一列__adb_auto_id__
,作為主鍵和分布鍵。此時主鍵只有__adb_auto_id__
,因為不包含分區鍵,所以報錯。
SQL錯誤示例2:
CREATE TABLE test (
id INT COMMENT '',
name VARCHAR(10) COMMENT ''
)
PARTITION BY VALUE(name) LIFECYCLE 30;
解決方法:請將分區鍵添加到主鍵中。
原因:AnalyticDB for MySQL集群有表數量上限,超過上限,會出現該報錯。不同產品系列不同產品規格的表數量上限不同,具體請參見內表數量的最大值。
解決方法:
刪除無用的表。
將多張表合并為一張表。
原因:AnalyticDB for MySQL不支持UNSIGNED屬性,即不支持無符號數。
解決方法:建表語句的列屬性中不定義UNSIGNED屬性。您需要自己在業務代碼中實現非負數的約束。
相關文檔
向表中寫入數據,請參見INSERT INTO。
將查詢結果寫入或覆蓋寫入,請參見INSERT SELECT FROM或INSERT OVERWRITE SELECT。
將RDS、MaxCompute、OSS或其他數據源的數據導入,請參見數據導入。