全部產品
Search
文件中心

:CREATE TABLE建立分區表與維表

更新時間:Jul 06, 2024

本文介紹AnalyticDB for MySQLCREATE 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:
  DISTRIBUTE BY HASH(column_name,...) | DISTRIBUTE 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

參數

說明

table_name

表名。表名以字母或底線(_)開頭,可包含字母、數字以及底線(_),長度為1到127個字元。

您可以使用db_name.table_name,指定在某個資料庫下建立表。

column_name

列名。列名以字母或底線(_)開頭,可包含字母、數字以及底線(_),長度為1到127個字元。

column_type

列的資料類型。AnalyticDB MySQL版支援的資料類型,請參見基礎資料類型複雜資料類型

COMMENT

為列或表添加備忘資訊。

column_attributes(預設值與自增列)

DEFAULT {constant | CURRENT_TIMESTAMP}

定義列的預設值。僅支援常量CURRENT_TIMESTAMP函數。不支援其他函數和Variant 運算式。

如果未指定預設值,則列的預設值為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或以上

說明

如何查看叢集核心版本,請參見如何查看執行個體版本資訊。如需升級核心版本,請聯絡支援人員。

文法[[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索引。

說明

如何查看叢集核心版本,請參見如何查看執行個體版本資訊。如需升級核心版本,請聯絡支援人員。

文法[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

        如何查看叢集核心版本,請參見如何查看執行個體版本資訊。如需升級核心版本,請聯絡支援人員。

      • 為JSON列中的指定屬性鍵建立索引時,若該JSON列已存在INDEX索引,需先刪除該列的INDEX索引,否則會報錯。

JSON Array索引

版本說明:

3.1.10.6及以上核心版本的叢集支援建立JSON Array索引。

說明

如何查看叢集核心版本,請參見如何查看執行個體版本資訊。如需升級核心版本,請聯絡支援人員。

文法[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

注意事項

  • 使用PARTITION BY定義分區時,必須同時定義生命週期LIFECYCLE N),否則會報錯。若不定義分區,資料不會被清理。

  • 建表後,不能增加分區鍵,也不支援增加、減少或變更修改分區鍵中的列。如果需要增加或修改分區鍵,請重建立表並遷移資料,具體操作請參見ALTER TABLE

調優建議:

  • 建議使用日期時間類型的欄位作為分區鍵。

  • 分區太大或太小都會影響查詢效能和寫入效能,甚至影響叢集的穩定性。建議的分區內資料行數以及查看分區是否合理,請參見分區欄位的合理性診斷

  • 不建議頻繁更新歷史分區的資料,例如,如果每天頻繁更新多個歷史分區,應考慮使用的分區鍵是否合理。

LIFECYCLE n

LIFECYCLE需要與PARTITION BY一起使用。定義每個分區最多保留n個分區,用於管理分區的生命週期。AnalyticDB for MySQL會根據分區鍵的值,從大到小對分區排序,保留前n個分區,超出n的分區將被刪除。您可以利用LIFECYCLE定義資料的保留時間長度。

例如,PARTITION BY VALUE (DATE_FORMAT(date, '%Y%m%d')) LIFECYCLE 30表示,將date列轉換為yyyyMMdd的格式並對資料分區,最多保留30個分區。假設第1天的資料寫入分區20231201,第2天的資料寫入分區20231201,依次類推,第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_timecustomer_idphone_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`)                                                                                                         |
|         | ) DISTRIBUTE 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__`)                                                                                                               |
|             | ) DISTRIBUTE 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)
) 
DISTRIBUTE 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)
) 
DISTRIBUTE 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)
) 
DISTRIBUTE 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)
) 
DISTRIBUTE 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)
) 
DISTRIBUTE BY HASH(xid) PARTITION BY VALUE(cid) LIFECYCLE 4;

更多關於向量索引和向量檢索的內容,請參見向量檢索

定義外鍵索引

新增一個名為store_returns的表,通過使用外鍵文法FOREIGN KEYsr_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索引

常見問題

列屬性和列約束

自增列是從1開始遞增嗎?值是唯一的嗎?

自增列的值不是順序遞增,也不支援從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,說明寫入分區鍵的值不符合資料類型的要求。

指定分區鍵時,能否使用除DATE_FORMAT以外的其他函數,例如PARTITION BY VALUE(FROM_UNIXTIME(col,'format'))?

不能。定義分區鍵僅支援兩種方法:PARTITION BY VALUE(column)和PARTITION BY VALUE(DATE_FORMAT(column,'format'))。使用其他函數會報錯。

如何查看分區表的生命週期?

通過SHOW CREATE TABLE <table_name>,查看建表語句。建表語句中顯示分區表的生命週期。

已設定資料只保留30天(即設定LIFECYCLE為30),為什麼還是可以查到30天以前的資料?

可能有兩個原因:

  • 分區剛剛到期,尚未被刪除。到期的分區資料不會被立即刪除。當該表的BUILD任務完成後,到期的分區資料才會被刪除。

  • LIFECYCLE定義了一個分區上保留多少個分區。當一個分區上,實際分區數小於LIFECYCLE設定值時,可能出現該現象。

    例如:

    • 資料分布不均。假設按日期分區,分區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查詢建表語句中定義的叢集索引。

是否支援唯一索引(UNIQUE INDEX)?

AnalyticDB for MySQL不支援唯一索引(UNIQUE INDEX)。但AnalyticDB for MySQL的主鍵索引就是唯一索引,可以確保主索引值在表中是唯一的。

列存

建表語句中的TABLE_PROPERTIES='{"format":"columnstore"}'是什麼意思?

TABLE_PROPERTIES='{"format":"columnstore"}'是固定取值,表示ENGINE中的資料是列存格式。建表時您無需手動指定該屬性。

其他

建表後,哪些參數可以通過ALTER TABLE變更?

ALTER TABLE支援變更以下參數:

  • table_name、column_name、column_type、COMMENT

  • 增加和刪除列(主鍵列除外)

  • 列的預設值

  • NOT NULL變更為NULL

  • 增加和刪除INDEX索引

  • 分區函數的日期格式

  • 生命週期

  • 儲存策略

具體用法請參見ALTER TABLE

其他參數在建表後無法變更。

一個叢集最多能夠建立多少個表?

一個AnalyticDB for MySQL叢集的表數量上限如下:

  • 數倉版預留模式叢集(具備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)

AnalyticDB for MySQL的預設字元集是什嗎?

AnalyticDB for MySQL預設的字元集為utf-8,相當於MySQL的utf8mb4字元集,暫不支援其他字元集。

常見報錯

partition number must larger than 0

原因:建表語句中定義了分區,但未設定分區的生命週期。

報錯的建表語句樣本如下:

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;

Only 204800 partition allowed, the number of existing partition=>196462

原因:AnalyticDB for MySQL叢集分區數量的上限預設為102400。分區數量超過上限,會出現該報錯。

查詢叢集的分區數量,方法如下。

SELECT count(partition_id)
FROM information_schema.kepler_partitions
WHERE partition_id > 0;

解決方案:您可以調整分區的粒度。例如,按天分區改為按月分區。修改分區粒度的操作,請參見ALTER TABLE

partition column 'XXX' is not found in primary index=> [YYY]

原因:主鍵需包含分布鍵和分區鍵。如果主鍵未包含分區鍵,會出現該報錯。

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;

解決方案:請將分區鍵添加到主鍵中。

SemanticException:only 5000 table allowed

原因:AnalyticDB for MySQL叢集有表數量上限,超過上限,會出現該報錯。不同產品系列不同產品規格的表數量上限不同,具體請參見內表數量的最大值

解決方案:

  • 刪除無用的表。

  • 將多張表合并為一張表。

unsigned expr not supported

原因:AnalyticDB for MySQL不支援UNSIGNED屬性,即不支援無符號數。

解決方案:建表語句的列屬性中不定義UNSIGNED屬性。您需要自己在業務代碼中實現非負數的約束。

相關文檔